From a760fd96233ae4e95e5b2667cdebc1aff92da800 Mon Sep 17 00:00:00 2001 From: Marek Gradzki Date: Tue, 21 Jun 2016 10:21:39 +0200 Subject: 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 Signed-off-by: Marek Gradzki --- .../v3po/interfaces/ip/AddressCustomizer.java | 107 ++++++++++++++++----- .../v3po/interfacesstate/InterfaceUtils.java | 6 +- .../interfacesstate/ip/Ipv4AddressCustomizer.java | 42 +++++--- .../v3po/interfacesstate/ip/Ipv4Customizer.java | 7 +- .../InterfacesStateHoneycombReaderModule.java | 4 +- 5 files changed, 114 insertions(+), 52 deletions(-) (limited to 'v3po/v3po2vpp/src/main') 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 { @@ -60,29 +61,30 @@ public class AddressCustomizer extends FutureJVppCustomizer implements ListWrite @Override public void writeCurrentAttributes(InstanceIdentifier
id, Address dataAfter, WriteContext writeContext) - throws WriteFailedException { + throws WriteFailedException { setAddress(true, id, dataAfter, writeContext); } @Override public void updateCurrentAttributes(InstanceIdentifier
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
id, Address dataBefore, WriteContext writeContext) - throws WriteFailedException { + throws WriteFailedException { setAddress(false, id, dataBefore, writeContext); } @Override public Optional> extract(InstanceIdentifier
currentId, DataObject parentData) { - return Optional.fromNullable((((Ipv4)parentData).getAddress())); + return Optional.fromNullable((((Ipv4) parentData).getAddress())); } - private void setAddress(boolean add,final InstanceIdentifier
id, final Address address, - final WriteContext writeContext) throws WriteFailedException { + private void setAddress(boolean add, final InstanceIdentifier
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
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
id, final String name, final int swIfc, - final Address address, final PrefixLength subnet) throws WriteFailedException { + private void setPrefixLengthSubnet(boolean add, final InstanceIdentifier
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 swInterfaceAddDelAddressReplyCompletionStage = getFutureJVpp() - .swInterfaceAddDelAddress(getSwInterfaceAddDelAddressRequest(swIfc, TranslateUtils.booleanToByte(add) /* isAdd */, + final CompletionStage 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 { + implements ListReaderCustomizer { 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
id) { return new AddressBuilder(); } @@ -68,7 +74,7 @@ public class Ipv4AddressCustomizer extends FutureJVppCustomizer @Override public void readCurrentAttributes(@Nonnull InstanceIdentifier
id, @Nonnull AddressBuilder builder, @Nonnull ReadContext ctx) - throws ReadFailedException { + throws ReadFailedException { LOG.debug("Reading attributes..."); Optional dumpOptional = dumpAddresses(id, ctx); @@ -77,15 +83,14 @@ public class Ipv4AddressCustomizer extends FutureJVppCustomizer List 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 getAllIds(@Nonnull InstanceIdentifier
id, @Nonnull ReadContext context) - throws ReadFailedException { + throws ReadFailedException { LOG.debug("Extracting keys.."); Optional dumpOptional = dumpAddresses(id, context); @@ -105,8 +110,8 @@ public class Ipv4AddressCustomizer extends FutureJVppCustomizer List 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 dumpAddresses(InstanceIdentifier
id, ReadContext ctx) - throws ReadFailedException { + throws ReadFailedException { Optional dumpFromCache = dumpAddressFromCache(ctx.getModificationCache()); if (dumpFromCache.isPresent()) { @@ -130,7 +135,7 @@ public class Ipv4AddressCustomizer extends FutureJVppCustomizer Optional 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 dumpAddressFromOperationalData() throws VppBaseCallException { + private Optional dumpAddressFromOperationalData(final InstanceIdentifier
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> getInterface1AugmentationReader() { final ChildReader
addressReader = new CompositeListReader<>(Address.class, - new Ipv4AddressCustomizer(getVppJvppDependency())); + new Ipv4AddressCustomizer(getVppJvppDependency(), getInterfaceContextIfcStateDependency())); final ChildReader> ipv4Reader = new CompositeChildReader<>(Ipv4.class, RWUtils.singletonChildReaderList(addressReader), - new Ipv4Customizer(getVppJvppDependency(), getInterfaceContextIfcStateDependency())); + new Ipv4Customizer(getVppJvppDependency())); final ChildReader> ipv6Reader = new CompositeChildReader<>(Ipv6.class, new Ipv6Customizer(getVppJvppDependency(), getInterfaceContextIfcStateDependency())); -- cgit 1.2.3-korg