diff options
author | Marek Gradzki <mgradzki@cisco.com> | 2016-06-21 10:21:39 +0200 |
---|---|---|
committer | Marek Gradzki <mgradzki@cisco.com> | 2016-06-21 15:12:00 +0200 |
commit | f19c503b83a5e9ac7205b47152e86159fe50b54a (patch) | |
tree | 7626114daec5523fd035a967e24eefe5468e8268 | |
parent | 1d154c992d712efc86fadd0d99c897c1d8e6bbbc (diff) |
HONEYCOMB-64: Add ipv4 netmask support
Supported contiguous netmask only
(strictly, only leading 1s are allowed)
Update postman collection
Change-Id: I989bbd013227bc3e1eda0861241543db0cdbf656
Signed-off-by: Tibor Sirovatka <tsirovat@cisco.com>
Signed-off-by: Marek Gradzki <mgradzki@cisco.com>
11 files changed, 571 insertions, 257 deletions
diff --git a/v3po/postman_rest_collection.json b/v3po/postman_rest_collection.json index 0a31f7b43..192f9ec50 100644 --- a/v3po/postman_rest_collection.json +++ b/v3po/postman_rest_collection.json @@ -18,10 +18,12 @@ "name": "IP", "description": "", "order": [ - "945138cf-d1f0-4674-b221-7b271010be42", - "a95120a1-5661-edc4-30cf-53afeb104440", - "6c5c9786-3619-ccaf-c276-0ada45711b70", - "3a93e78e-21ec-e0c9-94df-c69b60d9edcd" + "69a05849-026d-f120-5c6a-f3e2b0884d88", + "b10169c2-ae0e-bb1c-3dea-ca06839c6c9c", + "8d49cf41-facc-c4ac-cee7-475d50e2a0be", + "70835949-7252-a3cc-491b-f8aa69286399", + "d5a90cfd-fd7e-63b6-e1f1-16fc0671b0e1", + "3f7ee49b-ae11-b032-915f-a14bf838246f" ], "owner": "45557" }, @@ -257,27 +259,6 @@ "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"testInterface\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"enabled\": \"true\",\r\n \"link-up-down-trap-enable\": \"enabled\",\r\n \"ietf-ip:ipv4\": {\r\n \"enabled\": \"true\",\r\n \"mtu\": \"1500\",\r\n \"address\": [\r\n {\r\n \"ip\": \"1.2.3.0\",\r\n \"netmask\": \"255.255.255.0\"\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n \r\n}" }, { - "id": "3a93e78e-21ec-e0c9-94df-c69b60d9edcd", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0/ipv4", - "preRequestScript": "", - "pathVariables": {}, - "method": "GET", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1465473589796, - "name": "Read local0/ipv4 - cfg", - "description": "", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "folder": "7a914134-23ea-3154-1557-d29dc8d464e7", - "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"testInterface\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"enabled\": \"true\",\r\n \"link-up-down-trap-enable\": \"enabled\",\r\n \"ietf-ip:ipv4\": {\r\n \"enabled\": \"true\",\r\n \"mtu\": \"1500\",\r\n \"address\": [\r\n {\r\n \"ip\": \"1.2.3.0\",\r\n \"netmask\": \"255.255.255.0\"\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n \r\n}" - }, - { "id": "76e9ee89-1594-ff38-ffff-ffc8de5d4054", "headers": "Content-Type: application/json\nAuthorization: Basic YWRtaW46YWRtaW4=\n", "url": "http://localhost:8181/restconf/config/v3po:vpp/bridge-domains/bridge-domain/testBD", @@ -667,27 +648,6 @@ "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"testInterface\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"enabled\": \"true\",\r\n \"link-up-down-trap-enable\": \"enabled\",\r\n \"ietf-ip:ipv4\": {\r\n \"enabled\": \"true\",\r\n \"mtu\": \"1500\",\r\n \"address\": [\r\n {\r\n \"ip\": \"1.2.3.0\",\r\n \"netmask\": \"255.255.255.0\"\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n \r\n}" }, { - "id": "6c5c9786-3619-ccaf-c276-0ada45711b70", - "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/operational/ietf-interfaces:interfaces-state/interface/local0/ipv4", - "preRequestScript": "", - "pathVariables": {}, - "method": "GET", - "data": [], - "dataMode": "raw", - "version": 2, - "tests": "", - "currentHelper": "normal", - "helperAttributes": {}, - "time": 1465473594194, - "name": "Read local0/ipv4 - oper", - "description": "", - "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", - "responses": [], - "folder": "7a914134-23ea-3154-1557-d29dc8d464e7", - "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"testInterface\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"enabled\": \"true\",\r\n \"link-up-down-trap-enable\": \"enabled\",\r\n \"ietf-ip:ipv4\": {\r\n \"enabled\": \"true\",\r\n \"mtu\": \"1500\",\r\n \"address\": [\r\n {\r\n \"ip\": \"1.2.3.0\",\r\n \"netmask\": \"255.255.255.0\"\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n \r\n}" - }, - { "id": "7f312f15-a81e-b513-83b7-a5f7755eae67", "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/vhost1", @@ -772,7 +732,7 @@ "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"testInterface\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"enabled\": \"true\",\r\n \"link-up-down-trap-enable\": \"enabled\",\r\n \"ietf-ip:ipv4\": {\r\n \"enabled\": \"true\",\r\n \"mtu\": \"1500\",\r\n \"address\": [\r\n {\r\n \"ip\": \"1.2.3.0\",\r\n \"netmask\": \"255.255.255.0\"\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n \r\n}" }, { - "id": "945138cf-d1f0-4674-b221-7b271010be42", + "id": "69a05849-026d-f120-5c6a-f3e2b0884d88", "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", "url": "http://localhost:8181/restconf/operational/ietf-interfaces:interfaces-state/interface/local0", "preRequestScript": "", @@ -793,9 +753,9 @@ "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"testInterface\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"enabled\": \"true\",\r\n \"link-up-down-trap-enable\": \"enabled\",\r\n \"ietf-ip:ipv4\": {\r\n \"enabled\": \"true\",\r\n \"mtu\": \"1500\",\r\n \"address\": [\r\n {\r\n \"ip\": \"1.2.3.0\",\r\n \"netmask\": \"255.255.255.0\"\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n \r\n}" }, { - "id": "a95120a1-5661-edc4-30cf-53afeb104440", + "id": "b10169c2-ae0e-bb1c-3dea-ca06839c6c9c", "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", - "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0/ipv4", + "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0/ipv4/address/127.0.0.1", "preRequestScript": "", "pathVariables": {}, "method": "PUT", @@ -805,14 +765,99 @@ "tests": "", "currentHelper": "normal", "helperAttributes": {}, - "time": 1465472513661, + "time": 1466496859574, "name": "Set ipv4 local0 interface - cfg", "description": "", "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", "responses": [], "folder": "7a914134-23ea-3154-1557-d29dc8d464e7", - "rawModeData": "{\r\n\r\n \"ipv4\" : {\r\n \"address\": [{\r\n \"ip\" : \"127.0.0.1\",\r\n \"prefix-length\" : \"24\"\r\n }]\r\n }\r\n}" + "rawModeData": "{\r\n \"address\": [{\r\n \"ip\" : \"127.0.0.1\",\r\n \"prefix-length\" : \"24\"\r\n }]\r\n}" + }, + { + "id": "8d49cf41-facc-c4ac-cee7-475d50e2a0be", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0/ipv4/address/127.0.0.1", + "preRequestScript": "", + "pathVariables": {}, + "method": "DELETE", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1466497187475, + "name": "Remove ipv4 from local0 interface - cfg", + "description": "", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "folder": "7a914134-23ea-3154-1557-d29dc8d464e7", + "rawModeData": "" + }, + { + "id": "70835949-7252-a3cc-491b-f8aa69286399", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0/ipv4/address/127.0.0.1", + "preRequestScript": "", + "pathVariables": {}, + "method": "PUT", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1466497176571, + "name": "Set ipv4 local0 interface - cfg netmask", + "description": "", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "folder": "7a914134-23ea-3154-1557-d29dc8d464e7", + "rawModeData": "{\r\n \"address\": [{\r\n \"ip\" : \"127.0.0.1\",\r\n \"netmask\": \"255.255.255.128\"\r\n }]\r\n}" + }, + { + "id": "d5a90cfd-fd7e-63b6-e1f1-16fc0671b0e1", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/operational/ietf-interfaces:interfaces-state/interface/local0/ipv4", + "preRequestScript": "", + "pathVariables": {}, + "method": "GET", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1465473594194, + "name": "Read local0/ipv4 - oper", + "description": "", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "folder": "7a914134-23ea-3154-1557-d29dc8d464e7", + "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"testInterface\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"enabled\": \"true\",\r\n \"link-up-down-trap-enable\": \"enabled\",\r\n \"ietf-ip:ipv4\": {\r\n \"enabled\": \"true\",\r\n \"mtu\": \"1500\",\r\n \"address\": [\r\n {\r\n \"ip\": \"1.2.3.0\",\r\n \"netmask\": \"255.255.255.0\"\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n \r\n}" + }, + { + "id": "3f7ee49b-ae11-b032-915f-a14bf838246f", + "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", + "url": "http://localhost:8181/restconf/config/ietf-interfaces:interfaces/interface/local0/ipv4", + "preRequestScript": "", + "pathVariables": {}, + "method": "GET", + "data": [], + "dataMode": "raw", + "version": 2, + "tests": "", + "currentHelper": "normal", + "helperAttributes": {}, + "time": 1466497212835, + "name": "Read local0/ipv4 - cfg", + "description": "", + "collectionId": "7c35192d-9085-20f6-9fcd-3f8570aaefd7", + "responses": [], + "folder": "7a914134-23ea-3154-1557-d29dc8d464e7", + "rawModeData": "{\r\n \r\n \"interface\": [\r\n {\r\n \"name\": \"testInterface\",\r\n \"description\": \"for testing purposes\",\r\n \"type\": \"iana-if-type:ethernetCsmacd\",\r\n \"enabled\": \"true\",\r\n \"link-up-down-trap-enable\": \"enabled\",\r\n \"ietf-ip:ipv4\": {\r\n \"enabled\": \"true\",\r\n \"mtu\": \"1500\",\r\n \"address\": [\r\n {\r\n \"ip\": \"1.2.3.0\",\r\n \"netmask\": \"255.255.255.0\"\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n \r\n}" }, + { "id": "ac161bec-e046-4bb7-d695-60bdfb0c6cea", "headers": "Authorization: Basic YWRtaW46YWRtaW4=\nContent-Type: application/json\n", diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/AddressCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/AddressCustomizer.java index c99fcd29f..0b62bc027 100644 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/AddressCustomizer.java +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/AddressCustomizer.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package io.fd.honeycomb.v3po.translate.v3po.interfaces.ip; import static com.google.common.base.Preconditions.checkArgument; @@ -34,6 +35,8 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev14061 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.Subnet; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.Netmask; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.PrefixLength; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.PrefixLengthBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DottedQuad; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.openvpp.jvpp.VppBaseCallException; @@ -45,8 +48,6 @@ import org.slf4j.LoggerFactory; /** * Customizer for writing {@link Address} - * - * @author jsrnicek */ public class AddressCustomizer extends FutureJVppCustomizer implements ListWriterCustomizer<Address, AddressKey> { @@ -60,29 +61,30 @@ public class AddressCustomizer extends FutureJVppCustomizer implements ListWrite @Override public void writeCurrentAttributes(InstanceIdentifier<Address> id, Address dataAfter, WriteContext writeContext) - throws WriteFailedException { + throws WriteFailedException { setAddress(true, id, dataAfter, writeContext); } @Override public void updateCurrentAttributes(InstanceIdentifier<Address> id, Address dataBefore, Address dataAfter, - WriteContext writeContext) throws WriteFailedException { - throw new WriteFailedException.UpdateFailedException(id,dataBefore,dataAfter,new UnsupportedOperationException("Operation not supported")); + WriteContext writeContext) throws WriteFailedException { + throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, + new UnsupportedOperationException("Operation not supported")); } @Override public void deleteCurrentAttributes(InstanceIdentifier<Address> id, Address dataBefore, WriteContext writeContext) - throws WriteFailedException { + throws WriteFailedException { setAddress(false, id, dataBefore, writeContext); } @Override public Optional<List<Address>> extract(InstanceIdentifier<Address> currentId, DataObject parentData) { - return Optional.fromNullable((((Ipv4)parentData).getAddress())); + return Optional.fromNullable((((Ipv4) parentData).getAddress())); } - private void setAddress(boolean add,final InstanceIdentifier<Address> id, final Address address, - final WriteContext writeContext) throws WriteFailedException { + private void setAddress(boolean add, final InstanceIdentifier<Address> id, final Address address, + final WriteContext writeContext) throws WriteFailedException { final String interfaceName = id.firstKeyOf(Interface.class).getName(); final int swIfc = interfaceContext.getIndex(interfaceName, writeContext.getMappingContext()); @@ -90,9 +92,9 @@ public class AddressCustomizer extends FutureJVppCustomizer implements ListWrite Subnet subnet = address.getSubnet(); if (subnet instanceof PrefixLength) { - setPrefixLengthSubnet(add,id, interfaceName, swIfc, address, (PrefixLength) subnet); + setPrefixLengthSubnet(add, id, interfaceName, swIfc, address, (PrefixLength) subnet); } else if (subnet instanceof Netmask) { - setNetmaskSubnet(); + setNetmaskSubnet(add, id, interfaceName, swIfc, address, (Netmask) subnet); } else { // FIXME how does choice extensibility work // FIXME it is not even possible to create a dedicated @@ -105,40 +107,95 @@ public class AddressCustomizer extends FutureJVppCustomizer implements ListWrite } } - private void setNetmaskSubnet() { - // FIXME - throw new UnsupportedOperationException("Unimplemented"); + private void setNetmaskSubnet(final boolean add, final InstanceIdentifier<Address> id, final String name, + final int swIfc, + final Address ipv4Addr, final Netmask subnet) throws WriteFailedException { + LOG.debug("Setting Subnet(subnet-mask) for interface: {}, {}. Subnet: {}, Ipv4: {}", name, swIfc, subnet, + ipv4Addr); + + byte[] addr = TranslateUtils.ipv4AddressNoZoneToArray(ipv4Addr.getIp()); + final DottedQuad netmask = subnet.getNetmask(); + + checkNotNull(addr, "Null address"); + checkNotNull(netmask, "Null netmask"); + + // find netmask bit-length + final short subnetLength = getSubnetMaskLength(netmask.getValue()); + PrefixLengthBuilder lengthBuilder = new PrefixLengthBuilder().setPrefixLength(subnetLength); + + setPrefixLengthSubnet(add, id, name, swIfc, ipv4Addr, lengthBuilder.build()); + } + + /** + * Returns the prefix size in bits of the specified subnet mask. Example: For the subnet mask 255.255.255.128 it + * returns 25 while for 255.0.0.0 it returns 8. If the passed subnetMask array is not complete or contains not only + * leading ones, IllegalArgumentExpression is thrown + * + * @param mask the subnet mask in dot notation 255.255.255.255 + * @return the prefix length as number of bits + */ + private static short getSubnetMaskLength(final String mask) { + String[] maskParts = mask.split("\\."); + + final int DOTTED_QUAD_MASK_LENGHT = 4; + final int IPV4_ADDRESS_PART_BITS_COUNT = 8; + final int NETMASK_PART_LIMIT = 256; // 2 power to 8 + + checkArgument(maskParts.length == DOTTED_QUAD_MASK_LENGHT, + "Network mask %s is not in Quad Dotted Decimal notation!", mask); + + long maskAsNumber = 0; + for (int i = 0; i < DOTTED_QUAD_MASK_LENGHT; i++) { + maskAsNumber <<= IPV4_ADDRESS_PART_BITS_COUNT; + int value = Integer.parseInt(maskParts[i]); + checkArgument(value < NETMASK_PART_LIMIT, "Network mask %s contains invalid number(s) over 255!", mask); + checkArgument(value >= 0, "Network mask %s contains invalid negative number(s)!", mask); + maskAsNumber += value; + } + + String bits = Long.toBinaryString(maskAsNumber); + checkArgument(bits.length() == IPV4_ADDRESS_PART_BITS_COUNT * DOTTED_QUAD_MASK_LENGHT, + "Incorrect network mask %s", mask); + final int leadingOnes = bits.indexOf('0'); + checkArgument(leadingOnes != -1, "Broadcast address %s is not allowed!", mask); + checkArgument(bits.substring(leadingOnes).indexOf('1') == -1, + "Non-contiguous network mask %s is not allowed!", mask); + return (short) leadingOnes; } - private void setPrefixLengthSubnet(boolean add,final InstanceIdentifier<Address> id, final String name, final int swIfc, - final Address address, final PrefixLength subnet) throws WriteFailedException { + private void setPrefixLengthSubnet(boolean add, final InstanceIdentifier<Address> id, final String name, + final int swIfc, + final Address address, final PrefixLength subnet) throws WriteFailedException { try { - Short plen = subnet.getPrefixLength(); LOG.debug("Setting Subnet(prefix-length) for interface: {}, {}. Subnet: {}, Address: {}", name, swIfc, - subnet, address); - - byte[] addr = TranslateUtils.ipv4AddressNoZoneToArray(address.getIp()); + subnet, address); + final Short plen = subnet.getPrefixLength(); checkArgument(plen > 0, "Invalid length"); + + final byte[] addr = TranslateUtils.ipv4AddressNoZoneToArray(address.getIp()); checkNotNull(addr, "Null address"); - final CompletionStage<SwInterfaceAddDelAddressReply> swInterfaceAddDelAddressReplyCompletionStage = getFutureJVpp() - .swInterfaceAddDelAddress(getSwInterfaceAddDelAddressRequest(swIfc, TranslateUtils.booleanToByte(add) /* isAdd */, + final CompletionStage<SwInterfaceAddDelAddressReply> swInterfaceAddDelAddressReplyCompletionStage = + getFutureJVpp() + .swInterfaceAddDelAddress( + getSwInterfaceAddDelAddressRequest(swIfc, TranslateUtils.booleanToByte(add) /* isAdd */, (byte) 0 /* isIpv6 */, (byte) 0 /* delAll */, plen.byteValue(), addr)); TranslateUtils.getReply(swInterfaceAddDelAddressReplyCompletionStage.toCompletableFuture()); LOG.debug("Subnet(prefix-length) set successfully for interface: {}, {}, Subnet: {}, Address: {}", name, - swIfc, subnet, address); + swIfc, subnet, address); } catch (VppBaseCallException e) { LOG.warn("Failed to set Subnet(prefix-length) for interface: {}, {}, Subnet: {}, Address: {}", name, swIfc, - subnet, address); + subnet, address); throw new WriteFailedException(id, "Unable to handle subnet of type " + subnet.getClass(), e); } } private SwInterfaceAddDelAddress getSwInterfaceAddDelAddressRequest(final int swIfc, final byte isAdd, - final byte ipv6, final byte deleteAll, final byte length, final byte[] addr) { + final byte ipv6, final byte deleteAll, + final byte length, final byte[] addr) { final SwInterfaceAddDelAddress swInterfaceAddDelAddress = new SwInterfaceAddDelAddress(); swInterfaceAddDelAddress.swIfIndex = swIfc; swInterfaceAddDelAddress.isAdd = isAdd; diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceUtils.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceUtils.java index e2d3002d7..01a315a77 100644 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceUtils.java +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceUtils.java @@ -16,10 +16,10 @@ package io.fd.honeycomb.v3po.translate.v3po.interfacesstate; +import static com.google.common.base.Preconditions.checkArgument; import static io.fd.honeycomb.v3po.translate.v3po.interfacesstate.InterfaceCustomizer.getCachedInterfaceDump; import static java.util.Objects.requireNonNull; -import com.google.common.base.Preconditions; import io.fd.honeycomb.v3po.translate.ModificationCache; import io.fd.honeycomb.v3po.translate.read.ReadFailedException; import io.fd.honeycomb.v3po.translate.util.RWUtils; @@ -120,7 +120,7 @@ public final class InterfaceUtils { public static String vppPhysAddrToYang(@Nonnull final byte[] vppPhysAddress, int startIndex) { Objects.requireNonNull(vppPhysAddress, "Empty physical address bytes"); final int endIndex = startIndex + PHYSICAL_ADDRESS_LENGTH; - Preconditions.checkArgument(endIndex <= vppPhysAddress.length, + checkArgument(endIndex <= vppPhysAddress.length, "Invalid physical address size (%s) for given startIndex (%d), expected >= %d", vppPhysAddress.length, startIndex, endIndex); StringBuilder physAddr = new StringBuilder(); @@ -152,7 +152,7 @@ public final class InterfaceUtils { * @return VPP's representation of the if-index */ public static int yangIfIndexToVpp(int yangIfIndex) { - Preconditions.checkArgument(yangIfIndex >= 1, "YANG if-index has invalid value %s", yangIfIndex); + checkArgument(yangIfIndex >= 1, "YANG if-index has invalid value %s", yangIfIndex); return yangIfIndex - 1; } diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv4AddressCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv4AddressCustomizer.java index b52b0552a..6c8bb9447 100644 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv4AddressCustomizer.java +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv4AddressCustomizer.java @@ -17,18 +17,20 @@ package io.fd.honeycomb.v3po.translate.v3po.interfacesstate.ip; import com.google.common.base.Optional; +import io.fd.honeycomb.v3po.translate.MappingContext; import io.fd.honeycomb.v3po.translate.ModificationCache; import io.fd.honeycomb.v3po.translate.read.ReadContext; import io.fd.honeycomb.v3po.translate.read.ReadFailedException; import io.fd.honeycomb.v3po.translate.spi.read.ListReaderCustomizer; import io.fd.honeycomb.v3po.translate.util.RWUtils; import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; +import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils; -import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv4; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv4Builder; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.Address; @@ -50,17 +52,21 @@ import org.slf4j.LoggerFactory; * Customizer for read operations for {@link Address} of {@link Ipv4} */ public class Ipv4AddressCustomizer extends FutureJVppCustomizer - implements ListReaderCustomizer<Address, AddressKey, AddressBuilder> { + implements ListReaderCustomizer<Address, AddressKey, AddressBuilder> { private static final Logger LOG = LoggerFactory.getLogger(Ipv4AddressCustomizer.class); private static final String CACHE_KEY = Ipv4AddressCustomizer.class.getName(); - public Ipv4AddressCustomizer(FutureJVpp futureJvpp) { + private final NamingContext interfaceContext; + + public Ipv4AddressCustomizer(@Nonnull final FutureJVpp futureJvpp, @Nonnull final NamingContext interfaceContext) { super(futureJvpp); + this.interfaceContext = interfaceContext; } @Override + @Nonnull public AddressBuilder getBuilder(@Nonnull InstanceIdentifier<Address> id) { return new AddressBuilder(); } @@ -68,7 +74,7 @@ public class Ipv4AddressCustomizer extends FutureJVppCustomizer @Override public void readCurrentAttributes(@Nonnull InstanceIdentifier<Address> id, @Nonnull AddressBuilder builder, @Nonnull ReadContext ctx) - throws ReadFailedException { + throws ReadFailedException { LOG.debug("Reading attributes..."); Optional<IpAddressDetailsReplyDump> dumpOptional = dumpAddresses(id, ctx); @@ -77,15 +83,14 @@ public class Ipv4AddressCustomizer extends FutureJVppCustomizer List<IpAddressDetails> details = dumpOptional.get().ipAddressDetails; AddressKey key = id.firstKeyOf(Address.class); - byte[] identifingIpBytes = TranslateUtils.ipv4AddressNoZoneToArray(key.getIp()); IpAddressDetails detail = details.stream() - .filter(singleDetail -> Arrays.equals(identifingIpBytes, singleDetail.ip)) - .collect(RWUtils.singleItemCollector()); + .filter(singleDetail -> key.getIp().equals(TranslateUtils.arrayToIpv4AddressNoZone(singleDetail.ip))) + .collect(RWUtils.singleItemCollector()); builder.setIp(TranslateUtils.arrayToIpv4AddressNoZone(detail.ip)) - .setSubnet(new PrefixLengthBuilder() - .setPrefixLength(Short.valueOf(detail.prefixLength)).build()); + .setSubnet(new PrefixLengthBuilder() + .setPrefixLength(Short.valueOf(detail.prefixLength)).build()); LOG.info("Address read successfull"); } else { @@ -95,7 +100,7 @@ public class Ipv4AddressCustomizer extends FutureJVppCustomizer @Override public List<AddressKey> getAllIds(@Nonnull InstanceIdentifier<Address> id, @Nonnull ReadContext context) - throws ReadFailedException { + throws ReadFailedException { LOG.debug("Extracting keys.."); Optional<IpAddressDetailsReplyDump> dumpOptional = dumpAddresses(id, context); @@ -105,8 +110,8 @@ public class Ipv4AddressCustomizer extends FutureJVppCustomizer List<IpAddressDetails> details = dumpOptional.get().ipAddressDetails; return details.stream() - .map(detail -> new AddressKey(TranslateUtils.arrayToIpv4AddressNoZone(detail.ip))) - .collect(Collectors.toList()); + .map(detail -> new AddressKey(TranslateUtils.arrayToIpv4AddressNoZone(detail.ip))) + .collect(Collectors.toList()); } else { LOG.warn("No dump present"); return Collections.emptyList(); @@ -121,7 +126,7 @@ public class Ipv4AddressCustomizer extends FutureJVppCustomizer // TODO refactor after there is an more generic implementation of cache // operations private Optional<IpAddressDetailsReplyDump> dumpAddresses(InstanceIdentifier<Address> id, ReadContext ctx) - throws ReadFailedException { + throws ReadFailedException { Optional<IpAddressDetailsReplyDump> dumpFromCache = dumpAddressFromCache(ctx.getModificationCache()); if (dumpFromCache.isPresent()) { @@ -130,7 +135,7 @@ public class Ipv4AddressCustomizer extends FutureJVppCustomizer Optional<IpAddressDetailsReplyDump> dumpFromOperational; try { - dumpFromOperational = dumpAddressFromOperationalData(); + dumpFromOperational = dumpAddressFromOperationalData(id, ctx.getMappingContext()); } catch (VppBaseCallException e) { throw new ReadFailedException(id, e); } @@ -147,10 +152,15 @@ public class Ipv4AddressCustomizer extends FutureJVppCustomizer return Optional.fromNullable((IpAddressDetailsReplyDump) cache.get(CACHE_KEY)); } - private Optional<IpAddressDetailsReplyDump> dumpAddressFromOperationalData() throws VppBaseCallException { + private Optional<IpAddressDetailsReplyDump> dumpAddressFromOperationalData(final InstanceIdentifier<Address> id, + final MappingContext mappingContext) + throws VppBaseCallException { LOG.debug("Dumping from operational data..."); + final IpAddressDump dumpRequest = new IpAddressDump(); + dumpRequest.isIpv6 = 0; + dumpRequest.swIfIndex = interfaceContext.getIndex(id.firstKeyOf(Interface.class).getName(), mappingContext); return Optional.fromNullable( - TranslateUtils.getReply(getFutureJVpp().ipAddressDump(new IpAddressDump()).toCompletableFuture())); + TranslateUtils.getReply(getFutureJVpp().ipAddressDump(dumpRequest).toCompletableFuture())); } } diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv4Customizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv4Customizer.java index a10ad3ba5..8e6162784 100644 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv4Customizer.java +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv4Customizer.java @@ -20,7 +20,6 @@ import io.fd.honeycomb.v3po.translate.read.ReadContext; import io.fd.honeycomb.v3po.translate.read.ReadFailedException; import io.fd.honeycomb.v3po.translate.spi.read.ChildReaderCustomizer; import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer; -import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; import javax.annotation.Nonnull; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface2Builder; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv4; @@ -36,12 +35,8 @@ public class Ipv4Customizer extends FutureJVppCustomizer implements ChildReaderC private static final Logger LOG = LoggerFactory.getLogger(Ipv4Customizer.class); - //do not remove,it will be needed in future implementation - private final NamingContext interfaceContext; - - public Ipv4Customizer(@Nonnull final FutureJVpp futureJvpp, final NamingContext interfaceContext) { + public Ipv4Customizer(@Nonnull final FutureJVpp futureJvpp) { super(futureJvpp); - this.interfaceContext = interfaceContext; } @Override diff --git a/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/InterfacesStateHoneycombReaderModule.java b/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/InterfacesStateHoneycombReaderModule.java index 733942e4c..644a272a5 100644 --- a/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/InterfacesStateHoneycombReaderModule.java +++ b/v3po/v3po2vpp/src/main/java/org/opendaylight/yang/gen/v1/urn/honeycomb/params/xml/ns/yang/v3po2vpp/rev160406/InterfacesStateHoneycombReaderModule.java @@ -101,11 +101,11 @@ public class InterfacesStateHoneycombReaderModule extends private ChildReader<? extends Augmentation<Interface>> getInterface1AugmentationReader() { final ChildReader<Address> addressReader = new CompositeListReader<>(Address.class, - new Ipv4AddressCustomizer(getVppJvppDependency())); + new Ipv4AddressCustomizer(getVppJvppDependency(), getInterfaceContextIfcStateDependency())); final ChildReader<? extends ChildOf<Interface2>> ipv4Reader = new CompositeChildReader<>(Ipv4.class, RWUtils.singletonChildReaderList(addressReader), - new Ipv4Customizer(getVppJvppDependency(), getInterfaceContextIfcStateDependency())); + new Ipv4Customizer(getVppJvppDependency())); final ChildReader<? extends ChildOf<Interface2>> ipv6Reader = new CompositeChildReader<>(Ipv6.class, new Ipv6Customizer(getVppJvppDependency(), getInterfaceContextIfcStateDependency())); diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/AddressCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/AddressCustomizerTest.java index 9924e316d..3ad12e01c 100644 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/AddressCustomizerTest.java +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfaces/ip/AddressCustomizerTest.java @@ -1,23 +1,44 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + * + * 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 io.fd.honeycomb.v3po.translate.v3po.interfaces.ip; +import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.mockMapping; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; import com.google.common.base.Optional; import io.fd.honeycomb.v3po.translate.MappingContext; +import io.fd.honeycomb.v3po.translate.v3po.test.TestHelperUtils; import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; import io.fd.honeycomb.v3po.translate.write.WriteContext; import io.fd.honeycomb.v3po.translate.write.WriteFailedException; import java.util.Arrays; import java.util.List; import java.util.concurrent.CompletableFuture; +import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; -import org.mockito.Mockito; -import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; +import org.mockito.Mock; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces; @@ -28,126 +49,262 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev14061 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.Ipv4Builder; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.Address; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.AddressBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.Netmask; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.NetmaskBuilder; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.PrefixLength; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.PrefixLengthBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DottedQuad; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.VppInvocationException; import org.openvpp.jvpp.dto.SwInterfaceAddDelAddress; import org.openvpp.jvpp.dto.SwInterfaceAddDelAddressReply; import org.openvpp.jvpp.future.FutureJVpp; public class AddressCustomizerTest { - @Test - public void testWriteCurrentAttributes() throws WriteFailedException { + private static final String IFC_CTX_NAME = "ifc-test-instance"; + private static final String IFACE_NAME = "eth0"; + private static final int IFACE_ID = 123; - ArgumentCaptor<SwInterfaceAddDelAddress> requestCaptor = ArgumentCaptor.forClass(SwInterfaceAddDelAddress.class); + @Mock + private WriteContext writeContext; + @Mock + private MappingContext mappingContext; + @Mock + private FutureJVpp api; - FutureJVpp jvpp = mock(FutureJVpp.class); - WriteContext context = mock(WriteContext.class); - MappingContext mappingContext = mock(MappingContext.class); - NamingContext namingContext = new NamingContext("prefix", "instance"); + private NamingContext interfaceContext; + private AddressCustomizer customizer; - namingContext.addName(5, "parent", mappingContext); + @Before + public void setUp() throws Exception { + initMocks(this); + doReturn(mappingContext).when(writeContext).getMappingContext(); + interfaceContext = new NamingContext("generatedlIfaceName", IFC_CTX_NAME); - InterfaceKey key = new InterfaceKey("local0"); + customizer = new AddressCustomizer(api, interfaceContext); + } - InstanceIdentifier<Address> id = InstanceIdentifier.builder(Interfaces.class) - .child(Interface.class,key) - .augmentation(Interface1.class) - .child(Ipv4.class) - .child(Address.class) - .build(); + private static InstanceIdentifier<Address> getAddressId(final String ifaceName) { + return InstanceIdentifier.builder(Interfaces.class) + .child(Interface.class, new InterfaceKey(ifaceName)) + .augmentation(Interface1.class) + .child(Ipv4.class) + .child(Address.class) + .build(); + } - Mapping mapping = mock(Mapping.class); + private void whenSwInterfaceAddDelAddressThenSuccess() { + final CompletableFuture<SwInterfaceAddDelAddressReply> replyFuture = new CompletableFuture<>(); + final SwInterfaceAddDelAddressReply reply = new SwInterfaceAddDelAddressReply(); + replyFuture.complete(reply); + doReturn(replyFuture).when(api).swInterfaceAddDelAddress(any(SwInterfaceAddDelAddress.class)); + } - Ipv4AddressNoZone noZoneIp = new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")); + private void whenSwInterfaceAddDelAddressThenFailure() { + doReturn(TestHelperUtils.createFutureException()).when(api) + .swInterfaceAddDelAddress(any(SwInterfaceAddDelAddress.class)); + } - PrefixLength length = new PrefixLengthBuilder().setPrefixLength(new Integer(24).shortValue()).build(); - Address data = new AddressBuilder().setIp(noZoneIp).setSubnet(length).build(); + private void verifySwInterfaceAddDelAddressWasInvoked(final SwInterfaceAddDelAddress expected) throws + VppInvocationException { + ArgumentCaptor<SwInterfaceAddDelAddress> argumentCaptor = + ArgumentCaptor.forClass(SwInterfaceAddDelAddress.class); + verify(api).swInterfaceAddDelAddress(argumentCaptor.capture()); + verifySwInterfaceAddDelAddressWasInvoked(expected, argumentCaptor.getValue()); + } - CompletableFuture<SwInterfaceAddDelAddressReply> future = new CompletableFuture<>(); - future.complete(new SwInterfaceAddDelAddressReply()); + private void verifySwInterfaceAddDelAddressWasInvoked(final SwInterfaceAddDelAddress expected, + final SwInterfaceAddDelAddress actual) throws + VppInvocationException { + assertArrayEquals(expected.address, actual.address); + assertEquals(expected.addressLength, actual.addressLength); + assertEquals(expected.delAll, actual.delAll); + assertEquals(expected.isAdd, actual.isAdd); + assertEquals(expected.isIpv6, actual.isIpv6); + assertEquals(expected.swIfIndex, actual.swIfIndex); + } - when(context.getMappingContext()).thenReturn(mappingContext); - when(mapping.getIndex()).thenReturn(5); - when(mapping.getName()).thenReturn("local0"); - when(mappingContext.read(Mockito.any())).thenReturn(Optional.fromNullable(mapping)); - when(jvpp.swInterfaceAddDelAddress(Mockito.any(SwInterfaceAddDelAddress.class))).thenReturn(future); + @Test + public void testAddPrefixLengthIpv4Address() throws Exception { + final InstanceIdentifier<Address> id = getAddressId(IFACE_NAME); - new AddressCustomizer(jvpp, namingContext).writeCurrentAttributes(id, data, context); + Ipv4AddressNoZone noZoneIp = new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")); + PrefixLength length = new PrefixLengthBuilder().setPrefixLength(new Integer(24).shortValue()).build(); + Address data = new AddressBuilder().setIp(noZoneIp).setSubnet(length).build(); - verify(jvpp, times(1)).swInterfaceAddDelAddress(requestCaptor.capture()); + mockMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME); + whenSwInterfaceAddDelAddressThenSuccess(); - SwInterfaceAddDelAddress request = requestCaptor.getValue(); + customizer.writeCurrentAttributes(id, data, writeContext); - assertEquals(0, request.isIpv6); - assertEquals(1, request.isAdd); - assertEquals(0, request.delAll); - assertEquals(5, request.swIfIndex); - assertEquals(24, request.addressLength); - assertEquals(true,Arrays.equals(new byte[]{-64, -88, 2, 1}, request.address)); + verifySwInterfaceAddDelAddressWasInvoked(generateSwInterfaceAddDelAddressRequest(new byte[] {-64, -88, 2, 1}, + (byte) 1, (byte) 24)); } @Test - public void testDeleteCurrentAttributes() throws WriteFailedException { - ArgumentCaptor<SwInterfaceAddDelAddress> requestCaptor = ArgumentCaptor.forClass(SwInterfaceAddDelAddress.class); - - FutureJVpp jvpp = mock(FutureJVpp.class); - WriteContext context = mock(WriteContext.class); - MappingContext mappingContext = mock(MappingContext.class); - NamingContext namingContext = new NamingContext("prefix", "instance"); + public void testAddPrefixLengthIpv4AddressFailed() throws Exception { + final InstanceIdentifier<Address> id = getAddressId(IFACE_NAME); - namingContext.addName(5, "parent", mappingContext); + Ipv4AddressNoZone noZoneIp = new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")); + PrefixLength length = new PrefixLengthBuilder().setPrefixLength(new Integer(24).shortValue()).build(); + Address data = new AddressBuilder().setIp(noZoneIp).setSubnet(length).build(); - InterfaceKey key = new InterfaceKey("local0"); + mockMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME); + whenSwInterfaceAddDelAddressThenFailure(); + + try { + customizer.writeCurrentAttributes(id, data, writeContext); + } catch (WriteFailedException e) { + assertTrue(e.getCause() instanceof VppBaseCallException); + verifySwInterfaceAddDelAddressWasInvoked( + generateSwInterfaceAddDelAddressRequest(new byte[] {-64, -88, 2, 1}, + (byte) 1, (byte) 24)); + return; + } + fail("WriteFailedException was expected"); + } - InstanceIdentifier<Address> id = InstanceIdentifier.builder(Interfaces.class) - .child(Interface.class,key) - .augmentation(Interface1.class) - .child(Ipv4.class) - .child(Address.class) - .build(); + private SwInterfaceAddDelAddress generateSwInterfaceAddDelAddressRequest(final byte[] address, final byte isAdd, + final byte prefixLength) { + final SwInterfaceAddDelAddress request = new SwInterfaceAddDelAddress(); + request.swIfIndex = IFACE_ID; + request.isAdd = isAdd; + request.isIpv6 = 0; + request.delAll = 0; + request.addressLength = prefixLength; + request.address = address; + return request; + } - Mapping mapping = mock(Mapping.class); + @Test + public void testDeletePrefixLengthIpv4Address() throws Exception { + final InstanceIdentifier<Address> id = getAddressId(IFACE_NAME); Ipv4AddressNoZone noZoneIp = new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")); - PrefixLength length = new PrefixLengthBuilder().setPrefixLength(new Integer(24).shortValue()).build(); Address data = new AddressBuilder().setIp(noZoneIp).setSubnet(length).build(); - CompletableFuture<SwInterfaceAddDelAddressReply> future = new CompletableFuture<>(); - future.complete(new SwInterfaceAddDelAddressReply()); + mockMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME); + whenSwInterfaceAddDelAddressThenSuccess(); - when(context.getMappingContext()).thenReturn(mappingContext); - when(mapping.getIndex()).thenReturn(5); - when(mapping.getName()).thenReturn("local0"); - when(mappingContext.read(Mockito.any())).thenReturn(Optional.fromNullable(mapping)); - when(jvpp.swInterfaceAddDelAddress(Mockito.any(SwInterfaceAddDelAddress.class))).thenReturn(future); + customizer.deleteCurrentAttributes(id, data, writeContext); - new AddressCustomizer(jvpp, namingContext).deleteCurrentAttributes(id, data, context); + verifySwInterfaceAddDelAddressWasInvoked(generateSwInterfaceAddDelAddressRequest(new byte[] {-64, -88, 2, 1}, + (byte) 0, (byte) 24)); + } - verify(jvpp, times(1)).swInterfaceAddDelAddress(requestCaptor.capture()); + @Test + public void testDeletePrefixLengthIpv4AddressFailed() throws Exception { + final InstanceIdentifier<Address> id = getAddressId(IFACE_NAME); - SwInterfaceAddDelAddress request = requestCaptor.getValue(); + Ipv4AddressNoZone noZoneIp = new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")); + PrefixLength length = new PrefixLengthBuilder().setPrefixLength(new Integer(24).shortValue()).build(); + Address data = new AddressBuilder().setIp(noZoneIp).setSubnet(length).build(); - assertEquals(0, request.isIpv6); - assertEquals(0, request.isAdd); - assertEquals(0, request.delAll); - assertEquals(5, request.swIfIndex); - assertEquals(24, request.addressLength); - assertEquals(true,Arrays.equals(new byte[]{-64, -88, 2, 1}, request.address)); + mockMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME); + whenSwInterfaceAddDelAddressThenFailure(); + + try { + customizer.deleteCurrentAttributes(id, data, writeContext); + } catch (WriteFailedException e) { + assertTrue(e.getCause() instanceof VppBaseCallException); + verifySwInterfaceAddDelAddressWasInvoked( + generateSwInterfaceAddDelAddressRequest(new byte[] {-64, -88, 2, 1}, + (byte) 0, (byte) 24)); + return; + } + fail("WriteFailedException was expec16ted"); } @Test public void testExtract() { + final InstanceIdentifier<Address> id = getAddressId(IFACE_NAME); + Address address = new AddressBuilder().build(); Ipv4 parentData = new Ipv4Builder().setAddress(Arrays.asList(address)).build(); - Optional<List<Address>> addressesOptional = new AddressCustomizer(mock(FutureJVpp.class),null).extract(null, parentData); + Optional<List<Address>> addressesOptional = customizer.extract(id, parentData); + + assertEquals(true, addressesOptional.isPresent()); + assertEquals(1, addressesOptional.get().size()); + assertEquals(true, addressesOptional.get().contains(address)); + } + + private void testSingleNetmask(final int expectedPrefixLength, final String stringMask) throws Exception { + final InstanceIdentifier<Address> id = getAddressId(IFACE_NAME); - assertEquals(true,addressesOptional.isPresent()); - assertEquals(1,addressesOptional.get().size()); - assertEquals(true,addressesOptional.get().contains(address)); + Ipv4AddressNoZone noZoneIp = new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")); + Netmask subnet = new NetmaskBuilder().setNetmask(new DottedQuad(stringMask)).build(); + Address data = new AddressBuilder().setIp(noZoneIp).setSubnet(subnet).build(); + + mockMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME); + + final CompletableFuture<SwInterfaceAddDelAddressReply> replyFuture = new CompletableFuture<>(); + replyFuture.complete(new SwInterfaceAddDelAddressReply()); + ArgumentCaptor<SwInterfaceAddDelAddress> argumentCaptor = + ArgumentCaptor.forClass(SwInterfaceAddDelAddress.class); + doReturn(replyFuture).when(api).swInterfaceAddDelAddress(argumentCaptor.capture()); + + customizer.writeCurrentAttributes(id, data, writeContext); + + verifySwInterfaceAddDelAddressWasInvoked(generateSwInterfaceAddDelAddressRequest(new byte[] {-64, -88, 2, 1}, + (byte) 1, (byte) expectedPrefixLength), argumentCaptor.getValue()); + } + + private void testSingleIllegalNetmask(final String stringMask) throws Exception { + try { + final InstanceIdentifier<Address> id = getAddressId(IFACE_NAME); + + Ipv4AddressNoZone noZoneIp = new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")); + Netmask subnet = new NetmaskBuilder().setNetmask(new DottedQuad(stringMask)).build(); + Address data = new AddressBuilder().setIp(noZoneIp).setSubnet(subnet).build(); + + mockMapping(mappingContext, IFACE_NAME, IFACE_ID, IFC_CTX_NAME); + + final CompletableFuture<SwInterfaceAddDelAddressReply> replyFuture = new CompletableFuture<>(); + replyFuture.complete(new SwInterfaceAddDelAddressReply()); + ArgumentCaptor<SwInterfaceAddDelAddress> argumentCaptor = + ArgumentCaptor.forClass(SwInterfaceAddDelAddress.class); + doReturn(replyFuture).when(api).swInterfaceAddDelAddress(argumentCaptor.capture()); + + customizer.writeCurrentAttributes(id, data, writeContext); + } catch (IllegalArgumentException e) { + return; + } + fail("IllegalArgumentException expected"); + + } + + /** + * Test contiguous netmask length from QuadDotted notation + */ + @Test + public void testNetmaskLength() throws Exception { + testSingleNetmask(1, "128.0.0.0"); + testSingleNetmask(2, "192.0.0.0"); + testSingleNetmask(8, "255.0.0.0"); + testSingleNetmask(9, "255.128.0.0"); + testSingleNetmask(16, "255.255.0.0"); + testSingleNetmask(24, "255.255.255.0"); + } + + @Test + public void testNetmaskIllegal() throws Exception { + testSingleIllegalNetmask(""); + testSingleIllegalNetmask("."); + testSingleIllegalNetmask(".255"); + testSingleIllegalNetmask("255"); + testSingleIllegalNetmask("255."); + testSingleIllegalNetmask("255.255"); + testSingleIllegalNetmask("255.255.0"); + testSingleIllegalNetmask("255.255.255."); + testSingleIllegalNetmask("255.255.255.256"); + testSingleIllegalNetmask("0.0.0.0"); + testSingleIllegalNetmask("10.10.10.10"); + testSingleIllegalNetmask("255.1.255.0"); + testSingleIllegalNetmask("255.255.255.255"); } } diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceUtilsTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceUtilsTest.java index 0f45f1c83..c5781624a 100644 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceUtilsTest.java +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/InterfaceUtilsTest.java @@ -22,8 +22,8 @@ import org.junit.Test; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.EthernetCsmacd; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.Tap; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VhostUser; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanTunnel; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanGpeTunnel; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VxlanTunnel; public class InterfaceUtilsTest { diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv4AddressCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv4AddressCustomizerTest.java index 8008ba5bd..85f528e1e 100644 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv4AddressCustomizerTest.java +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/v3po/translate/v3po/interfacesstate/ip/Ipv4AddressCustomizerTest.java @@ -16,17 +16,23 @@ package io.fd.honeycomb.v3po.translate.v3po.interfacesstate.ip; +import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMapping; +import static io.fd.honeycomb.v3po.translate.v3po.test.ContextTestUtils.getMappingIid; +import static io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils.reverseBytes; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import com.google.common.base.Optional; import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; import io.fd.honeycomb.v3po.translate.ModificationCache; -import io.fd.honeycomb.v3po.translate.read.ReadContext; import io.fd.honeycomb.v3po.translate.read.ReadFailedException; +import io.fd.honeycomb.v3po.translate.spi.read.RootReaderCustomizer; +import io.fd.honeycomb.v3po.translate.v3po.test.ListReaderCustomizerTest; +import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext; import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils; import java.util.Arrays; import java.util.List; @@ -34,10 +40,15 @@ import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; import org.junit.Test; import org.mockito.Mockito; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.Mappings; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.MappingsBuilder; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.Mapping; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.naming.context.rev160513.contexts.naming.context.mappings.MappingKey; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface2; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv4; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.Ipv4Builder; @@ -45,64 +56,93 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev14061 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.AddressBuilder; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces.state._interface.ipv4.AddressKey; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; import org.openvpp.jvpp.dto.IpAddressDetails; import org.openvpp.jvpp.dto.IpAddressDetailsReplyDump; import org.openvpp.jvpp.dto.IpAddressDump; -import org.openvpp.jvpp.future.FutureJVpp; -public class Ipv4AddressCustomizerTest { +public class Ipv4AddressCustomizerTest extends ListReaderCustomizerTest<Address, AddressKey, AddressBuilder> { - @Test - public void testGetBuilder() { - assertNotNull(new Ipv4AddressCustomizer(mock(FutureJVpp.class)).getBuilder(null)); + private static final String IFACE_NAME = "eth0"; + private static final int IFACE_ID = 1; + + private NamingContext interfacesContext; + + public Ipv4AddressCustomizerTest() { + super(Address.class); + } + + @Override + public void setUpBefore() { + interfacesContext = new NamingContext("generatedIfaceName", "test-instance"); + } + + @Override + protected RootReaderCustomizer<Address, AddressBuilder> initCustomizer() { + final KeyedInstanceIdentifier<Mapping, MappingKey> eth0Id = getMappingIid(IFACE_NAME, "test-instance"); + final Optional<Mapping> eth0 = getMapping(IFACE_NAME, IFACE_ID); + + final List<Mapping> allMappings = Lists.newArrayList(getMapping(IFACE_NAME, IFACE_ID).get()); + final Mappings allMappingsBaObject = new MappingsBuilder().setMapping(allMappings).build(); + doReturn(Optional.of(allMappingsBaObject)).when(mappingContext).read(eth0Id.firstIdentifierOf(Mappings.class)); + + doReturn(eth0).when(mappingContext).read(eth0Id); + + return new Ipv4AddressCustomizer(api, interfacesContext); + } + + private static InstanceIdentifier<Address> getId(final String address) { + return InstanceIdentifier.builder(InterfacesState.class) + .child(Interface.class, new InterfaceKey(IFACE_NAME)) + .augmentation(Interface2.class) + .child(Ipv4.class) + .child(Address.class, new AddressKey(new Ipv4AddressNoZone(new Ipv4Address(address)))) + .build(); } @Test public void testReadCurrentAttributesFromCache() throws ReadFailedException { - ReadContext context = mock(ReadContext.class); ModificationCache cache = new ModificationCache(); - FutureJVpp jvpp = mock(FutureJVpp.class); IpAddressDetails detail1 = new IpAddressDetails(); IpAddressDetails detail2 = new IpAddressDetails(); IpAddressDetails detail3 = new IpAddressDetails(); - detail1.ip = TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1"))); - detail2.ip = TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.2"))); - detail3.ip = TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.3"))); + detail1.ip = reverseBytes( + TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")))); + detail2.ip = reverseBytes( + TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.2")))); + detail3.ip = reverseBytes( + TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.3")))); IpAddressDetailsReplyDump reply = new IpAddressDetailsReplyDump(); reply.ipAddressDetails = ImmutableList.of(detail1, detail2, detail3); cache.put(Ipv4AddressCustomizer.class.getName(), reply); - when(context.getModificationCache()).thenReturn(cache); + when(ctx.getModificationCache()).thenReturn(cache); - AddressBuilder builder = new AddressBuilder(); - InstanceIdentifier<Address> id = InstanceIdentifier.builder(InterfacesState.class) - .child(Interface.class) - .augmentation(Interface2.class) - .child(Ipv4.class) - .child(Address.class, new AddressKey(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")))) - .build(); + final AddressBuilder builder = new AddressBuilder(); + final InstanceIdentifier<Address> id = getId("192.168.2.1"); - new Ipv4AddressCustomizer(jvpp).readCurrentAttributes(id, builder, context); + getCustomizer().readCurrentAttributes(id, builder, ctx); - assertEquals("1.2.168.192", builder.getIp().getValue()); + assertEquals("192.168.2.1", builder.getIp().getValue()); } @Test public void testReadCurrentAttributesFromOperationalData() throws ReadFailedException { - ReadContext context = mock(ReadContext.class); ModificationCache cache = new ModificationCache(); - FutureJVpp jvpp = mock(FutureJVpp.class); IpAddressDetails detail1 = new IpAddressDetails(); IpAddressDetails detail2 = new IpAddressDetails(); IpAddressDetails detail3 = new IpAddressDetails(); - detail1.ip = TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1"))); - detail2.ip = TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.2"))); - detail3.ip = TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.3"))); + detail1.ip = reverseBytes( + TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")))); + detail2.ip = reverseBytes( + TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.2")))); + detail3.ip = reverseBytes( + TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.3")))); IpAddressDetailsReplyDump reply = new IpAddressDetailsReplyDump(); reply.ipAddressDetails = ImmutableList.of(detail1, detail2, detail3); @@ -110,65 +150,66 @@ public class Ipv4AddressCustomizerTest { CompletableFuture<IpAddressDetailsReplyDump> future = new CompletableFuture<>(); future.complete(reply); - when(jvpp.ipAddressDump(Mockito.any(IpAddressDump.class))).thenReturn(future); - when(context.getModificationCache()).thenReturn(cache); + when(api.ipAddressDump(Mockito.any(IpAddressDump.class))).thenReturn(future); + when(ctx.getModificationCache()).thenReturn(cache); + - AddressBuilder builder = new AddressBuilder(); - InstanceIdentifier<Address> id = InstanceIdentifier.builder(InterfacesState.class) - .child(Interface.class) - .augmentation(Interface2.class) - .child(Ipv4.class) - .child(Address.class, new AddressKey(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")))) - .build(); + final AddressBuilder builder = new AddressBuilder(); + final InstanceIdentifier<Address> id = getId("192.168.2.1"); - new Ipv4AddressCustomizer(jvpp).readCurrentAttributes(id, builder, context); + getCustomizer().readCurrentAttributes(id, builder, ctx); - assertEquals("1.2.168.192", builder.getIp().getValue()); + assertEquals("192.168.2.1", builder.getIp().getValue()); } @Test public void testGetAllIdsFromCache() throws ReadFailedException { - ReadContext context = mock(ReadContext.class); ModificationCache cache = new ModificationCache(); - FutureJVpp jvpp = mock(FutureJVpp.class); IpAddressDetails detail1 = new IpAddressDetails(); IpAddressDetails detail2 = new IpAddressDetails(); IpAddressDetails detail3 = new IpAddressDetails(); - detail1.ip = TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1"))); - detail2.ip = TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.2"))); - detail3.ip = TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.3"))); + detail1.ip = reverseBytes( + TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")))); + detail2.ip = reverseBytes( + TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.2")))); + detail3.ip = reverseBytes( + TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.3")))); IpAddressDetailsReplyDump reply = new IpAddressDetailsReplyDump(); reply.ipAddressDetails = ImmutableList.of(detail1, detail2, detail3); cache.put(Ipv4AddressCustomizer.class.getName(), reply); - when(context.getModificationCache()).thenReturn(cache); - List<Ipv4AddressNoZone> ids = new Ipv4AddressCustomizer(jvpp).getAllIds(null, context).stream() - .map(id -> id.getIp()) - .collect(Collectors.toList()); + when(ctx.getModificationCache()).thenReturn(cache); - verify(jvpp, times(0)).ipAddressDump(Mockito.any(IpAddressDump.class)); + final InstanceIdentifier<Address> id = getId("192.168.2.1"); + + List<Ipv4AddressNoZone> ids = getCustomizer().getAllIds(id, ctx).stream() + .map(key -> key.getIp()) + .collect(Collectors.toList()); + + verify(api, times(0)).ipAddressDump(Mockito.any(IpAddressDump.class)); assertEquals(3, ids.size()); - assertEquals(true, "1.2.168.192".equals(ids.get(0).getValue())); - assertEquals(true, "2.2.168.192".equals(ids.get(1).getValue())); - assertEquals(true, "3.2.168.192".equals(ids.get(2).getValue())); + assertEquals(true, "192.168.2.1".equals(ids.get(0).getValue())); + assertEquals(true, "192.168.2.2".equals(ids.get(1).getValue())); + assertEquals(true, "192.168.2.3".equals(ids.get(2).getValue())); } @Test public void testGetAllIdsFromOperationalData() throws ReadFailedException { - ReadContext context = mock(ReadContext.class); ModificationCache cache = new ModificationCache(); - FutureJVpp jvpp = mock(FutureJVpp.class); IpAddressDetails detail1 = new IpAddressDetails(); IpAddressDetails detail2 = new IpAddressDetails(); IpAddressDetails detail3 = new IpAddressDetails(); - detail1.ip = TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1"))); - detail2.ip = TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.2"))); - detail3.ip = TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.3"))); + detail1.ip = reverseBytes( + TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.1")))); + detail2.ip = reverseBytes( + TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.2")))); + detail3.ip = reverseBytes( + TranslateUtils.ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(new Ipv4Address("192.168.2.3")))); IpAddressDetailsReplyDump reply = new IpAddressDetailsReplyDump(); reply.ipAddressDetails = ImmutableList.of(detail1, detail2, detail3); @@ -176,16 +217,19 @@ public class Ipv4AddressCustomizerTest { CompletableFuture<IpAddressDetailsReplyDump> future = new CompletableFuture<>(); future.complete(reply); - when(jvpp.ipAddressDump(Mockito.any(IpAddressDump.class))).thenReturn(future); - when(context.getModificationCache()).thenReturn(cache); - List<Ipv4AddressNoZone> ids = new Ipv4AddressCustomizer(jvpp).getAllIds(null, context).stream() - .map(id -> id.getIp()) - .collect(Collectors.toList()); + when(api.ipAddressDump(Mockito.any(IpAddressDump.class))).thenReturn(future); + when(ctx.getModificationCache()).thenReturn(cache); + + final InstanceIdentifier<Address> id = getId("192.168.2.1"); + + List<Ipv4AddressNoZone> ids = getCustomizer().getAllIds(id, ctx).stream() + .map(key -> key.getIp()) + .collect(Collectors.toList()); assertEquals(3, ids.size()); - assertEquals(true, "1.2.168.192".equals(ids.get(0).getValue())); - assertEquals(true, "2.2.168.192".equals(ids.get(1).getValue())); - assertEquals(true, "3.2.168.192".equals(ids.get(2).getValue())); + assertEquals(true, "192.168.2.1".equals(ids.get(0).getValue())); + assertEquals(true, "192.168.2.2".equals(ids.get(1).getValue())); + assertEquals(true, "192.168.2.3".equals(ids.get(2).getValue())); } @Test @@ -193,7 +237,7 @@ public class Ipv4AddressCustomizerTest { Address address = new AddressBuilder().build(); Ipv4Builder ipv4Builder = new Ipv4Builder(); - new Ipv4AddressCustomizer(mock(FutureJVpp.class)).merge(ipv4Builder, Arrays.asList(address)); + getCustomizer().merge(ipv4Builder, Arrays.asList(address)); assertEquals(1, ipv4Builder.getAddress().size()); assertEquals(true, ipv4Builder.getAddress().contains(address)); diff --git a/v3po/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/TranslateUtils.java b/v3po/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/TranslateUtils.java index 77e60877f..d44bf8fd5 100644 --- a/v3po/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/TranslateUtils.java +++ b/v3po/vpp-translate-utils/src/main/java/io/fd/honeycomb/v3po/translate/v3po/util/TranslateUtils.java @@ -185,4 +185,19 @@ public final class TranslateUtils { } throw new IllegalArgumentException(String.format("0 or 1 was expected but was %d", value)); } + + /** + * Reverses bytes in the byte array + * @param bytes input array + * @return reversed array + */ + public static byte[] reverseBytes(final byte[] bytes) { + final byte[] reversed = new byte[bytes.length]; + int i = 1; + for (byte aByte : bytes) { + reversed[bytes.length - i++] = aByte; + } + + return reversed; + } } diff --git a/v3po/vpp-translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/v3po/util/TranslateUtilsTest.java b/v3po/vpp-translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/v3po/util/TranslateUtilsTest.java index ba3861b99..89e7d9d89 100644 --- a/v3po/vpp-translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/v3po/util/TranslateUtilsTest.java +++ b/v3po/vpp-translate-utils/src/test/java/io/fd/honeycomb/v3po/translate/v3po/util/TranslateUtilsTest.java @@ -1,5 +1,6 @@ package io.fd.honeycomb.v3po.translate.v3po.util; +import static io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils.reverseBytes; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; @@ -19,16 +20,6 @@ public class TranslateUtilsTest { assertEquals(ipv4Addr, ipv4AddressNoZone); } - private byte[] reverseBytes(final byte[] bytes) { - final byte[] reversed = new byte[bytes.length]; - int i = 1; - for (byte aByte : bytes) { - reversed[bytes.length - i++] = aByte; - } - - return reversed; - } - @Test public void testToString() { final byte[] expected = "test".getBytes(); |