diff options
Diffstat (limited to 'acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write')
12 files changed, 843 insertions, 373 deletions
diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/VppAclCustomizer.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/AclCustomizer.java index 00cd8a56c..1161c09ef 100644 --- a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/VppAclCustomizer.java +++ b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/AclCustomizer.java @@ -19,26 +19,25 @@ package io.fd.hc2vpp.acl.write; import io.fd.hc2vpp.acl.util.AclContextManager; import io.fd.hc2vpp.acl.util.FutureJVppAclCustomizer; import io.fd.hc2vpp.acl.util.acl.AclDataExtractor; -import io.fd.hc2vpp.acl.util.acl.AclWriter; -import io.fd.honeycomb.translate.MappingContext; +import io.fd.hc2vpp.acl.write.request.AclAddReplaceRequest; import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer; import io.fd.honeycomb.translate.write.WriteContext; import io.fd.honeycomb.translate.write.WriteFailedException; import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade; import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.AclKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev181001.acls.Acl; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev181001.acls.AclKey; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -public class VppAclCustomizer extends FutureJVppAclCustomizer - implements ListWriterCustomizer<Acl, AclKey>, AclDataExtractor, AclWriter { +public class AclCustomizer extends FutureJVppAclCustomizer + implements ListWriterCustomizer<Acl, AclKey>, AclDataExtractor { private final AclContextManager standardAclContext; private final AclContextManager macIpAclContext; - public VppAclCustomizer(@Nonnull final FutureJVppAclFacade jVppAclFacade, - @Nonnull final AclContextManager standardAclContext, - @Nonnull final AclContextManager macIpAclContext) { + public AclCustomizer(@Nonnull final FutureJVppAclFacade jVppAclFacade, + @Nonnull final AclContextManager standardAclContext, + @Nonnull final AclContextManager macIpAclContext) { super(jVppAclFacade); this.standardAclContext = standardAclContext; this.macIpAclContext = macIpAclContext; @@ -47,12 +46,11 @@ public class VppAclCustomizer extends FutureJVppAclCustomizer @Override public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl dataAfter, @Nonnull final WriteContext writeContext) throws WriteFailedException { - final MappingContext mappingContext = writeContext.getMappingContext(); - + AclAddReplaceRequest request = new AclAddReplaceRequest(getjVppAclFacade(), writeContext.getMappingContext()); if (isStandardAcl(dataAfter)) { - addStandardAcl(getjVppAclFacade(), id, dataAfter, standardAclContext, mappingContext); + request.addStandardAcl(id, dataAfter, standardAclContext); } else if (isMacIpAcl(dataAfter)) { - addMacIpAcl(getjVppAclFacade(), id, dataAfter, macIpAclContext, mappingContext); + request.addMacIpAcl(id, dataAfter, macIpAclContext); } else { // double check, first one done by validation throw new WriteFailedException.CreateFailedException(id, dataAfter, @@ -64,17 +62,17 @@ public class VppAclCustomizer extends FutureJVppAclCustomizer public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl dataBefore, @Nonnull final Acl dataAfter, @Nonnull final WriteContext writeContext) throws WriteFailedException { - final MappingContext mappingContext = writeContext.getMappingContext(); + AclAddReplaceRequest request = new AclAddReplaceRequest(getjVppAclFacade(), writeContext.getMappingContext()); if (isStandardAcl(dataAfter)) { - updateStandardAcl(getjVppAclFacade(), id, dataAfter, standardAclContext, mappingContext); + request.updateStandardAcl(id, dataAfter, standardAclContext); } else if (isMacIpAcl(dataAfter)) { synchronized (macIpAclContext) { // there is no direct support for update of mac-ip acl, but only one is allowed per interface // so it is atomic from vpp standpoint. Enclosed in synchronized block to prevent issues with // multiple threads managing naming context - deleteMacIpAcl(getjVppAclFacade(), id, dataBefore, macIpAclContext, mappingContext); - addMacIpAcl(getjVppAclFacade(), id, dataAfter, macIpAclContext, mappingContext); + request.deleteMacIpAcl(id, dataBefore, macIpAclContext); + request.addMacIpAcl(id, dataAfter, macIpAclContext); } } else { // double check, first one done by validation @@ -86,12 +84,12 @@ public class VppAclCustomizer extends FutureJVppAclCustomizer @Override public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl dataBefore, @Nonnull final WriteContext writeContext) throws WriteFailedException { - final MappingContext mappingContext = writeContext.getMappingContext(); + AclAddReplaceRequest request = new AclAddReplaceRequest(getjVppAclFacade(), writeContext.getMappingContext()); if (isStandardAcl(dataBefore)) { - deleteStandardAcl(getjVppAclFacade(), id, dataBefore, standardAclContext, mappingContext); + request.deleteStandardAcl(id, dataBefore, standardAclContext); } else if (isMacIpAcl(dataBefore)) { - deleteMacIpAcl(getjVppAclFacade(), id, dataBefore, macIpAclContext, mappingContext); + request.deleteMacIpAcl(id, dataBefore, macIpAclContext); } else { // double check, first one done by validation throw new WriteFailedException.DeleteFailedException(id, diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/AclValidator.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/AclValidator.java new file mode 100644 index 000000000..b7aaebcff --- /dev/null +++ b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/AclValidator.java @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2018 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.hc2vpp.acl.write; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkState; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableSet; +import io.fd.hc2vpp.acl.AclIIds; +import io.fd.hc2vpp.acl.util.acl.AclDataExtractor; +import io.fd.honeycomb.translate.write.DataValidationFailedException.CreateValidationFailedException; +import io.fd.honeycomb.translate.write.DataValidationFailedException.DeleteValidationFailedException; +import io.fd.honeycomb.translate.write.DataValidationFailedException.UpdateValidationFailedException; +import io.fd.honeycomb.translate.write.Validator; +import io.fd.honeycomb.translate.write.WriteContext; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.vpp.acl.rev181022.VppAcl; +import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.vpp.acl.rev181022.VppMacipAcl; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev181001.AclBase; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev181001.acls.Acl; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev181001.acls.AttachmentPoints; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev181001.acls.acl.Aces; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev181001.acls.acl.aces.Ace; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev181001.acls.acl.aces.ace.Matches; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev181001.acls.acl.aces.ace.matches.L3; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev181001.acls.acl.aces.ace.matches.l2.Eth; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev181001.acls.acl.aces.ace.matches.l3.Ipv4; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev181001.acls.acl.aces.ace.matches.l3.Ipv6; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev181001.acls.attachment.points.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev181001.acls.attachment.points._interface.acl.AclSets; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev181001.acls.attachment.points._interface.acl.acl.sets.AclSet; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev181001.acl.ipv4.header.fields.source.network.SourceIpv4Network; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev181001.acl.ipv6.header.fields.source.network.SourceIpv6Network; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public final class AclValidator implements Validator<Acl>, AclDataExtractor { + + private static final Set<Class<? extends AclBase>> SUPPORTED_ACL_TYPES = + ImmutableSet.of(VppAcl.class, VppMacipAcl.class); + + @Override + public void validateWrite(final InstanceIdentifier<Acl> id, final Acl dataAfter, final WriteContext ctx) + throws CreateValidationFailedException { + try { + validateAcl(dataAfter); + } catch (RuntimeException e) { + throw new CreateValidationFailedException(id, dataAfter, e); + } + } + + @Override + public void validateUpdate(final InstanceIdentifier<Acl> id, final Acl dataBefore, final Acl dataAfter, + final WriteContext ctx) throws UpdateValidationFailedException { + try { + validateAcl(dataAfter); + } catch (RuntimeException e) { + throw new UpdateValidationFailedException(id, dataBefore, dataAfter, e); + } + } + + @Override + public void validateDelete(final InstanceIdentifier<Acl> id, final Acl dataBefore, final WriteContext ctx) + throws DeleteValidationFailedException { + try { + validateAcl(dataBefore); + final List<String> references = checkAclReferenced(ctx, dataBefore); + // references must be check, to not leave dead references in configuration + checkState(references.isEmpty(), + "%s cannot be removed, it is referenced in following interfaces %s", dataBefore, references); + } catch (RuntimeException e) { + throw new DeleteValidationFailedException(id, e); + } + } + + private static void validateAcl(@Nonnull final Acl acl) { + hasAceList(acl); + isSupportedAclType(acl); + hasConsistentAceTypeForAclType(acl); + } + + private static void hasAceList(final Acl acl) { + final Aces accessListEntries = acl.getAces(); + checkArgument(accessListEntries != null, "The access-list-entries container is not defined."); + final List<Ace> ace = accessListEntries.getAce(); + checkArgument(ace != null, "The ace list is not defined."); + checkArgument(!ace.isEmpty(), "The ace list is empty."); + } + + private static void isSupportedAclType(final Acl acl) { + checkArgument(SUPPORTED_ACL_TYPES.contains(acl.getType()), + "Unsupported Acl type %s detected for acl %s, allowed types are %s", acl.getType(), + acl.getName(), SUPPORTED_ACL_TYPES); + } + + private static void hasConsistentAceTypeForAclType(final Acl acl) { + Class<? extends AclBase> type = acl.getType(); + Preconditions.checkNotNull(type, "Cannot resolve Acl type for validation of Acl: {}", acl); + Preconditions.checkNotNull(acl.getAces(), "ACEs are missing for validation of Acl: {}", acl); + Preconditions.checkNotNull(acl.getAces().getAce(), "List of ACEs is null for validation of Acl: {}", acl); + if (type.equals(VppAcl.class)) { + Set<Ace> unsupportedVppAcls = + acl.getAces().getAce().stream().filter(ace -> !isVppAce(ace)).collect(Collectors.toSet()); + checkArgument(unsupportedVppAcls.isEmpty(), "Detected unsupported ace types [%s] for ACL %s", + unsupportedVppAcls, acl.getName()); + } + + if (type.equals(VppMacipAcl.class)) { + Set<Ace> unsupportedVppMacipAclAcls = + acl.getAces().getAce().stream().filter(ace -> !isVppMacipAclAce(ace)).collect(Collectors.toSet()); + checkArgument(unsupportedVppMacipAclAcls.isEmpty(), "Detected unsupported ace types [%s] for ACL %s", + unsupportedVppMacipAclAcls, acl.getName()); + } + } + + private static boolean isVppMacipAclAce(final Ace ace) { + Matches matches = Preconditions + .checkNotNull(ace.getMatches(), "Cannot validate VppMacipAcl type for Ace: {}, matches are not defined", + ace); + if (matches.getL2() == null || !(matches.getL2() instanceof Eth)) { + return false; + } + + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev181001.acls.acl.aces.ace.matches.l2.eth.Eth + eth = ((Eth) matches.getL2()).getEth(); + if (eth == null) { + return false; + } + + return true; + } + + private static boolean isVppAce(final Ace ace) { + Matches matches = Preconditions + .checkNotNull(ace.getMatches(), "Cannot validate VppMacipAcl type for Ace: {}, matches are not defined", + ace); + L3 l3 = matches.getL3(); + if (l3 == null || (!(l3 instanceof Ipv4)) && (!(l3 instanceof Ipv6))) { + return false; + } + + if (l3 instanceof Ipv4) { + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev181001.acls.acl.aces.ace.matches.l3.ipv4.Ipv4 + ipv4 = ((Ipv4) l3).getIpv4(); + if (ipv4 == null || ipv4.getSourceNetwork() == null || + !(ipv4.getSourceNetwork() instanceof SourceIpv4Network)) { + return false; + } + } + + if (l3 instanceof Ipv6) { + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev181001.acls.acl.aces.ace.matches.l3.ipv6.Ipv6 + ipv6 = ((Ipv6) l3).getIpv6(); + if (ipv6 == null || ipv6.getSourceNetwork() == null || + !(ipv6.getSourceNetwork() instanceof SourceIpv6Network)) { + return false; + } + } + + return true; + } + + @VisibleForTesting + static List<String> checkAclReferenced(@Nonnull final WriteContext writeContext, @Nonnull final Acl acl) { + Preconditions.checkNotNull(acl.getType(), "Cannot validate acl: {}, type is not set.", acl); + if (!acl.getType().equals(VppAcl.class) && !acl.getType().equals(VppMacipAcl.class)) { + throw new IllegalArgumentException(String.format("Acl type %s not supported", acl.getType())); + } + + Optional<AttachmentPoints> attachmentPointsOpt = writeContext.readAfter(AclIIds.ACLS_AP); + if (!attachmentPointsOpt.isPresent() || attachmentPointsOpt.get().getInterface() == null) { + return Collections.emptyList(); + } + + final List<Interface> interfaces = attachmentPointsOpt.get().getInterface(); + if (interfaces == null) { + return Collections.emptyList(); + } + final String aclName = acl.getName(); + + HashMap<String, AclSets> sets = getIngressAclSets(interfaces); + sets.putAll(getEgressAclSets(interfaces)); + List<String> referencedIfcs = new ArrayList<>(); + sets.forEach((ifc, aclSets) -> { + if (aclSets.getAclSet() != null) { + if (aclSets.getAclSet().stream() + .map(AclSet::getName) + .filter(Objects::nonNull) + .anyMatch(name -> name.equalsIgnoreCase(aclName))) { + referencedIfcs.add(ifc); + } + } + }); + return referencedIfcs.stream().distinct().collect(Collectors.toList()); + } + + private static HashMap<String, AclSets> getEgressAclSets(final List<Interface> interfaces) { + HashMap<String, AclSets> map = new HashMap<>(); + interfaces.stream().filter(anInterface -> anInterface.getEgress() != null) + .forEach(anInterface -> map.put(anInterface.getInterfaceId(), anInterface.getEgress().getAclSets())); + return map; + } + + private static HashMap<String, AclSets> getIngressAclSets(final List<Interface> interfaces) { + HashMap<String, AclSets> map = new HashMap<>(); + interfaces.stream().filter(anInterface -> anInterface.getIngress() != null) + .forEach(anInterface -> map.put(anInterface.getInterfaceId(), anInterface.getIngress().getAclSets())); + return map; + } +} diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/InterfaceAclCustomizer.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/InterfaceAclCustomizer.java index a6ca35af3..622a84d93 100644 --- a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/InterfaceAclCustomizer.java +++ b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/InterfaceAclCustomizer.java @@ -16,82 +16,177 @@ package io.fd.hc2vpp.acl.write; +import static io.fd.hc2vpp.acl.write.request.MacIpInterfaceAssignmentRequest.deleteExisting; import static java.util.stream.Collectors.toList; import io.fd.hc2vpp.acl.util.AclContextManager; import io.fd.hc2vpp.acl.util.FutureJVppAclCustomizer; -import io.fd.hc2vpp.acl.util.iface.acl.AclInterfaceAssignmentRequest; +import io.fd.hc2vpp.acl.write.request.AclInterfaceAssignmentRequest; +import io.fd.hc2vpp.acl.write.request.MacIpInterfaceAssignmentRequest; import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.MappingContext; import io.fd.honeycomb.translate.spi.write.WriterCustomizer; import io.fd.honeycomb.translate.write.WriteContext; import io.fd.honeycomb.translate.write.WriteFailedException; import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade; import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.VppAclsBaseAttributes; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214._interface.acl.attributes.Acl; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.vpp.acls.base.attributes.VppAcls; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev181001.acls.attachment.points.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev181001.acls.attachment.points._interface.acl.AclSets; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev181001.acls.attachment.points._interface.acl.acl.sets.AclSet; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; /** * Handles acl assignments(only standard ones, mac-ip have dedicated customizer) */ -public class InterfaceAclCustomizer extends FutureJVppAclCustomizer implements WriterCustomizer<Acl> { +public class InterfaceAclCustomizer extends FutureJVppAclCustomizer implements WriterCustomizer<Interface> { private final NamingContext interfaceContext; private final AclContextManager standardAclContext; + private final AclContextManager macIpAclContext; public InterfaceAclCustomizer(@Nonnull final FutureJVppAclFacade jVppAclFacade, @Nonnull final NamingContext interfaceContext, - @Nonnull final AclContextManager standardAclContext) { + @Nonnull final AclContextManager standardAclContext, + @Nonnull final AclContextManager macIpAclContext) { super(jVppAclFacade); this.interfaceContext = interfaceContext; this.standardAclContext = standardAclContext; + this.macIpAclContext = macIpAclContext; + } + + private static List<String> getAclNames(final AclSets acls) { + if (acls == null || acls.getAclSet() == null) { + return Collections.emptyList(); + } else { + return acls.getAclSet().stream().map(AclSet::getName).collect(toList()); + } } @Override - public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl dataAfter, + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Interface> id, + @Nonnull final Interface dataAfter, @Nonnull final WriteContext writeContext) throws WriteFailedException { - AclInterfaceAssignmentRequest.create(writeContext.getMappingContext()) - .standardAclContext(standardAclContext) - .interfaceContext(interfaceContext) - .identifier(id) - .inputAclNames(getAclNames(dataAfter.getIngress())) - .outputAclNames(getAclNames(dataAfter.getEgress())) - .executeAsCreate(getjVppAclFacade()); + AclSets egress = dataAfter.getEgress() != null ? dataAfter.getEgress().getAclSets() : null; + AclSets ingress = dataAfter.getIngress() != null ? dataAfter.getIngress().getAclSets() : null; + List<String> macIngress = parseMacRules(getAclNames(ingress), writeContext.getMappingContext()); + List<String> standardIngress = parseStandardRules(getAclNames(ingress), writeContext.getMappingContext()); + List<String> standardEgress = parseStandardRules(getAclNames(egress), writeContext.getMappingContext()); + + // Process standard ACLs + if (!standardIngress.isEmpty() || !standardEgress.isEmpty()) { + AclInterfaceAssignmentRequest.create(writeContext.getMappingContext()) + .standardAclContext(standardAclContext) + .interfaceContext(interfaceContext) + .identifier(id) + .inputAclNames(standardIngress) + .outputAclNames(standardEgress) + .executeAsCreate(getjVppAclFacade()); + } + // Process mac ACLs + if (!macIngress.isEmpty()) { + addMacAcls(id, writeContext, macIngress); + } } @Override - public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl dataBefore, - @Nonnull final Acl dataAfter, @Nonnull final WriteContext writeContext) + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Interface> id, + @Nonnull final Interface dataBefore, + @Nonnull final Interface dataAfter, @Nonnull final WriteContext writeContext) throws WriteFailedException { + AclSets egress = dataAfter.getEgress() != null ? dataAfter.getEgress().getAclSets() : null; + AclSets ingress = dataAfter.getIngress() != null ? dataAfter.getIngress().getAclSets() : null; + List<String> standardIngress = parseStandardRules(getAclNames(ingress), writeContext.getMappingContext()); + List<String> standardEgress = parseStandardRules(getAclNames(egress), writeContext.getMappingContext()); + + // update standard ACLs AclInterfaceAssignmentRequest.create(writeContext.getMappingContext()) .standardAclContext(standardAclContext) .interfaceContext(interfaceContext) .identifier(id) - .inputAclNames(getAclNames(dataAfter.getIngress())) - .outputAclNames(getAclNames(dataAfter.getEgress())) + .inputAclNames(standardIngress) + .outputAclNames(standardEgress) .executeAsUpdate(getjVppAclFacade(), dataBefore, dataAfter); + + // Process mac ACLs + AclSets ingressBefore = dataBefore.getIngress() != null ? dataBefore.getIngress().getAclSets() : null; + List<String> macIngressAfter = parseMacRules(getAclNames(ingress), writeContext.getMappingContext()); + List<String> macIngressBefore = parseMacRules(getAclNames(ingressBefore), writeContext.getMappingContext()); + List<String> added = + macIngressAfter.stream().filter(acl -> !macIngressBefore.contains(acl)).collect(Collectors.toList()); + List<String> removed = + macIngressBefore.stream().filter(acl -> !macIngressAfter.contains(acl)).collect(Collectors.toList()); + + if (!removed.isEmpty()) { + deleteMacACLs(id, writeContext, removed); + } + + if (!added.isEmpty()) { + addMacAcls(id, writeContext, added); + } } @Override - public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl dataBefore, - @Nonnull final WriteContext writeContext) throws WriteFailedException { - AclInterfaceAssignmentRequest.create(writeContext.getMappingContext()) - .standardAclContext(standardAclContext) - .interfaceContext(interfaceContext) - .identifier(id) - .executeAsDelete(getjVppAclFacade()); + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Interface> id, + @Nonnull final Interface dataBefore, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + AclSets ingress = dataBefore.getIngress() != null ? dataBefore.getIngress().getAclSets() : null; + List<String> standardIngress = parseStandardRules(getAclNames(ingress), writeContext.getMappingContext()); + List<String> macIngress = parseMacRules(getAclNames(ingress), writeContext.getMappingContext()); + + //Process standard ACLs + if (!standardIngress.isEmpty()) { + AclInterfaceAssignmentRequest.create(writeContext.getMappingContext()) + .standardAclContext(standardAclContext) + .interfaceContext(interfaceContext) + .identifier(id) + .executeAsDelete(getjVppAclFacade()); + } + + // Process mac ACLs + if (!macIngress.isEmpty()) { + deleteMacACLs(id, writeContext, macIngress); + } } - private static List<String> getAclNames(final VppAclsBaseAttributes acls) { - if (acls == null || acls.getVppAcls() == null) { - return Collections.emptyList(); - } else { - return acls.getVppAcls().stream().map(VppAcls::getName).collect(toList()); + private List<String> parseMacRules(final List<String> ingress, final MappingContext mappingContext) { + return ingress.stream() + .filter(aclName -> macIpAclContext.containsAcl(aclName, mappingContext)).collect(Collectors.toList()); + } + + private List<String> parseStandardRules(final List<String> ingress, final MappingContext mappingContext) { + return ingress.stream() + .filter(aclName -> standardAclContext.containsAcl(aclName, mappingContext)) + .collect(Collectors.toList()); + } + + + private void addMacAcls(@Nonnull final InstanceIdentifier<Interface> id, + @Nonnull final WriteContext writeContext, final List<String> added) + throws WriteFailedException { + for (String macAcl : added) { + MacIpInterfaceAssignmentRequest.addNew(writeContext.getMappingContext()) + .identifier(id) + .aclName(macAcl) + .macIpAclContext(macIpAclContext) + .interfaceContext(interfaceContext) + .execute(getjVppAclFacade()); } } + private void deleteMacACLs(@Nonnull final InstanceIdentifier<Interface> id, + @Nonnull final WriteContext writeContext, final List<String> macAcls) + throws WriteFailedException { + for (String macAcl : macAcls) { + deleteExisting(writeContext.getMappingContext()) + .identifier(id) + .aclName(macAcl) + .macIpAclContext(macIpAclContext) + .interfaceContext(interfaceContext) + .execute(getjVppAclFacade()); + } + } } diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/InterfaceAclMacIpCustomizer.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/InterfaceAclMacIpCustomizer.java deleted file mode 100644 index fc0acd223..000000000 --- a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/InterfaceAclMacIpCustomizer.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 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.hc2vpp.acl.write; - -import static io.fd.hc2vpp.acl.util.iface.macip.MacIpInterfaceAssignmentRequest.addNew; -import static io.fd.hc2vpp.acl.util.iface.macip.MacIpInterfaceAssignmentRequest.deleteExisting; - -import io.fd.hc2vpp.acl.util.AclContextManager; -import io.fd.hc2vpp.acl.util.FutureJVppAclCustomizer; -import io.fd.hc2vpp.common.translate.util.NamingContext; -import io.fd.honeycomb.translate.spi.write.WriterCustomizer; -import io.fd.honeycomb.translate.write.WriteContext; -import io.fd.honeycomb.translate.write.WriteFailedException; -import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.vpp.macip.acls.base.attributes.VppMacipAcl; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -public class InterfaceAclMacIpCustomizer extends FutureJVppAclCustomizer implements WriterCustomizer<VppMacipAcl> { - - private final AclContextManager macIpAclContext; - private final NamingContext interfaceContext; - - public InterfaceAclMacIpCustomizer(@Nonnull final FutureJVppAclFacade jVppAclFacade, - @Nonnull final AclContextManager macIpAclContext, - @Nonnull final NamingContext interfaceContext) { - super(jVppAclFacade); - this.macIpAclContext = macIpAclContext; - this.interfaceContext = interfaceContext; - } - - @Override - public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<VppMacipAcl> id, - @Nonnull final VppMacipAcl dataAfter, - @Nonnull final WriteContext writeContext) throws WriteFailedException { - addNew(writeContext.getMappingContext()) - .identifier(id) - .aclName(dataAfter.getName()) - .macIpAclContext(macIpAclContext) - .interfaceContext(interfaceContext) - .execute(getjVppAclFacade()); - } - - @Override - public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<VppMacipAcl> id, - @Nonnull final VppMacipAcl dataBefore, - @Nonnull final WriteContext writeContext) throws WriteFailedException { - deleteExisting(writeContext.getMappingContext()) - .identifier(id) - .aclName(dataBefore.getName()) - .macIpAclContext(macIpAclContext) - .interfaceContext(interfaceContext) - .execute(getjVppAclFacade()); - } -} diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/VppAclValidator.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/VppAclValidator.java deleted file mode 100644 index 942d3bcb3..000000000 --- a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/VppAclValidator.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (c) 2018 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.hc2vpp.acl.write; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; -import static java.lang.String.format; -import static java.util.Collections.emptyList; -import static java.util.Optional.ofNullable; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Optional; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import io.fd.hc2vpp.acl.util.acl.AclDataExtractor; -import io.fd.honeycomb.translate.write.DataValidationFailedException.CreateValidationFailedException; -import io.fd.honeycomb.translate.write.DataValidationFailedException.DeleteValidationFailedException; -import io.fd.honeycomb.translate.write.DataValidationFailedException.UpdateValidationFailedException; -import io.fd.honeycomb.translate.write.Validator; -import io.fd.honeycomb.translate.write.WriteContext; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.AclBase; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.AccessListEntries; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.Ace; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.Matches; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.AceType; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.InterfaceAclAttributes; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.VppAclInterfaceAugmentation; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.VppAclsBaseAttributes; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.VppMacipAclsBaseAttributes; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev170615.VppAcl; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev170615.VppMacipAcl; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev170615.access.lists.acl.access.list.entries.ace.matches.ace.type.VppAce; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev170615.access.lists.acl.access.list.entries.ace.matches.ace.type.VppMacipAce; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -public final class VppAclValidator implements Validator<Acl>, AclDataExtractor { - - private static final Set<Class<? extends AclBase>> SUPPORTED_ACL_TYPES = - ImmutableSet.of(VppAcl.class, VppMacipAcl.class); - private static final Map<Class<? extends AclBase>, Class<? extends AceType>> ACL_ACE_PAIRS = - ImmutableMap.of(VppAcl.class, VppAce.class, VppMacipAcl.class, VppMacipAce.class); - - @Override - public void validateWrite(final InstanceIdentifier<Acl> id, final Acl dataAfter, final WriteContext ctx) - throws CreateValidationFailedException { - try { - validateAcl(dataAfter); - } catch (RuntimeException e) { - throw new CreateValidationFailedException(id, dataAfter, e); - } - } - - @Override - public void validateUpdate(final InstanceIdentifier<Acl> id, final Acl dataBefore, final Acl dataAfter, - final WriteContext ctx) throws UpdateValidationFailedException { - try { - validateAcl(dataAfter); - } catch (RuntimeException e) { - throw new UpdateValidationFailedException(id, dataBefore, dataAfter, e); - } - } - - @Override - public void validateDelete(final InstanceIdentifier<Acl> id, final Acl dataBefore, final WriteContext ctx) - throws DeleteValidationFailedException { - try { - validateAcl(dataBefore); - final List<Interface> references = checkAclReferenced(ctx, dataBefore); - // references must be check, to not leave dead references in configuration - checkState(references.isEmpty(), - "%s cannot be removed, it is referenced in following interfaces %s", dataBefore, references); - } catch (RuntimeException e) { - throw new DeleteValidationFailedException(id, e); - } - } - - private static void validateAcl(@Nonnull final Acl acl) { - hasAceList(acl); - isSupportedAclType(acl); - hasConsistentAceTypeForAclType(acl); - } - - private static void hasAceList(final Acl acl) { - final AccessListEntries accessListEntries = acl.getAccessListEntries(); - checkArgument(accessListEntries != null, "The access-list-entries container is not defined."); - final List<Ace> ace = accessListEntries.getAce(); - checkArgument(ace != null, "The ace list is not defined."); - checkArgument(!ace.isEmpty(), "The ace list is empty."); - } - - private static void isSupportedAclType(final Acl acl) { - checkArgument(SUPPORTED_ACL_TYPES.contains(acl.getAclType()), - "Unsupported Acl type %s detected for acl %s, allowed types are %s", acl.getAclType(), - acl.getAclName(), SUPPORTED_ACL_TYPES); - } - - private static void hasConsistentAceTypeForAclType(final Acl acl) { - checkTypesSame(acl.getAccessListEntries().getAce(), acl.getAclName(), - checkNotNull(ACL_ACE_PAIRS.get(acl.getAclType()), "Unsupported ACL type %s for ACL %s", - acl.getAclType(), acl.getAclName())); - } - - private static void checkTypesSame(final List<Ace> aces, final String aclName, - final Class<? extends AceType> aceType) { - final Set<AceType> unsupportedAceTypes = aces.stream() - .map(Ace::getMatches) - .map(Matches::getAceType) - .filter(aceType::equals) - .collect(Collectors.toSet()); - checkArgument(unsupportedAceTypes.isEmpty(), "Detected unsupported ace types [%s] for ACL %s, expected %s", - unsupportedAceTypes, aclName, aceType); - } - - @VisibleForTesting - static List<Interface> checkAclReferenced(@Nonnull final WriteContext writeContext, - @Nonnull final Acl acl) { - final Optional<Interfaces> readAfter = writeContext.readAfter(InstanceIdentifier.create(Interfaces.class)); - if (!readAfter.isPresent() || readAfter.get().getInterface() == null) { - return Collections.emptyList(); - } - - final List<Interface> interfaces = readAfter.get().getInterface(); - final Class<? extends AclBase> aclType = acl.getAclType(); - final String aclName = acl.getAclName(); - - if (aclType.equals(VppAcl.class)) { - return interfaces.stream() - .filter(iface -> ofNullable(iface.augmentation(VppAclInterfaceAugmentation.class)) - .map(InterfaceAclAttributes::getAcl) - .filter(references -> - checkVppAcls(references.getIngress(), aclName) || - checkVppAcls(references.getEgress(), aclName)).isPresent() - ).collect(Collectors.toList()); - } else if (aclType.equals(VppMacipAcl.class)) { - return interfaces.stream() - .filter(iface -> ofNullable(iface.augmentation(VppAclInterfaceAugmentation.class)) - .map(InterfaceAclAttributes::getAcl) - .map(aclAttr -> aclAttr.getIngress()) - .map(VppMacipAclsBaseAttributes::getVppMacipAcl) - .filter(vppMacipAcl -> vppMacipAcl.getName().equals(aclName)) - .isPresent()) - .collect(Collectors.toList()); - } else { - throw new IllegalArgumentException(format("Acl type %s not supported", aclType)); - } - } - - private static boolean checkVppAcls(@Nullable final VppAclsBaseAttributes attrs, @Nonnull final String name) { - return ofNullable(attrs).map(VppAclsBaseAttributes::getVppAcls) - .orElse(emptyList()) - .stream().anyMatch(acl -> acl.getName().equals(name)); - } -} diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/factory/AbstractAclWriterFactory.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/factory/AbstractAclWriterFactory.java index 37a8de2d1..8944e5977 100644 --- a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/factory/AbstractAclWriterFactory.java +++ b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/factory/AbstractAclWriterFactory.java @@ -26,10 +26,10 @@ import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade; /** * Created by jsrnicek on 12.12.2016. */ -class AbstractAclWriterFactory { +abstract class AbstractAclWriterFactory { @Inject - protected FutureJVppAclFacade futureAclFacade; + FutureJVppAclFacade futureAclFacade; @Inject @Named(AclModule.STANDARD_ACL_CONTEXT_NAME) @@ -37,7 +37,7 @@ class AbstractAclWriterFactory { @Inject @Named(AclModule.MAC_IP_ACL_CONTEXT_NAME) - protected AclContextManager macIpAClContext; + protected AclContextManager macIpAclContext; @Inject @Named("interface-context") diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/factory/AclWriterFactory.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/factory/AclWriterFactory.java new file mode 100644 index 000000000..faab3023d --- /dev/null +++ b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/factory/AclWriterFactory.java @@ -0,0 +1,39 @@ +/* + * 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.hc2vpp.acl.write.factory; + +import io.fd.hc2vpp.acl.AclIIds; +import io.fd.hc2vpp.acl.write.AclCustomizer; +import io.fd.hc2vpp.acl.write.AclValidator; +import io.fd.honeycomb.translate.impl.write.GenericListWriter; +import io.fd.honeycomb.translate.write.WriterFactory; +import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder; +import javax.annotation.Nonnull; + +public class AclWriterFactory extends AbstractAclWriterFactory implements WriterFactory { + + @Override + public void init(@Nonnull final ModifiableWriterRegistryBuilder registry) { + + registry.subtreeAddBefore(AclIIds.vppAclChildren(AclIIds.ACL), + new GenericListWriter<>(AclIIds.ACLS_ACL, + new AclCustomizer(futureAclFacade, standardAclContext, macIpAclContext), + new AclValidator() + ), + AclIIds.aclHandledChildren(AclIIds.IFC_ACL)); + } +} diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/factory/InterfaceAclWriterFactory.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/factory/InterfaceAclWriterFactory.java index 12be40a14..c5144b362 100644 --- a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/factory/InterfaceAclWriterFactory.java +++ b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/factory/InterfaceAclWriterFactory.java @@ -17,46 +17,27 @@ package io.fd.hc2vpp.acl.write.factory; import com.google.common.collect.ImmutableSet; +import io.fd.hc2vpp.acl.AclIIds; import io.fd.hc2vpp.acl.write.InterfaceAclCustomizer; -import io.fd.hc2vpp.acl.write.InterfaceAclMacIpCustomizer; import io.fd.honeycomb.translate.impl.write.GenericWriter; import io.fd.honeycomb.translate.write.WriterFactory; import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder; import java.util.Set; import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.VppAclInterfaceAugmentation; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214._interface.acl.attributes.Acl; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214._interface.acl.attributes.acl.Egress; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214._interface.acl.attributes.acl.Ingress; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.vpp.acls.base.attributes.VppAcls; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.vpp.macip.acls.base.attributes.VppMacipAcl; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; public class InterfaceAclWriterFactory extends AbstractAclWriterFactory implements WriterFactory { - static final InstanceIdentifier<Acl> ACL_IID = - InstanceIdentifier.create(Interfaces.class).child(Interface.class) - .augmentation(VppAclInterfaceAugmentation.class).child(Acl.class); - private static final InstanceIdentifier<Interface> IFC_ID = - InstanceIdentifier.create(Interfaces.class).child(Interface.class); - - @Override public void init(@Nonnull final ModifiableWriterRegistryBuilder registry) { - registry.subtreeAddAfter(aclHandledChildren(InstanceIdentifier.create(Acl.class)), - new GenericWriter<>(ACL_IID, - new InterfaceAclCustomizer(futureAclFacade, interfaceContext, standardAclContext)), IFC_ID); - - registry.addAfter(new GenericWriter<>(ACL_IID.child(Ingress.class).child(VppMacipAcl.class), - new InterfaceAclMacIpCustomizer(futureAclFacade, macIpAClContext, interfaceContext)), IFC_ID); + registry.subtreeAddAfter(AclIIds.aclHandledChildren(AclIIds.IFC_ACL), + new GenericWriter<>(AclIIds.ACLS_AP_INT, + new InterfaceAclCustomizer(futureAclFacade, interfaceContext, standardAclContext, + macIpAclContext)), + aclRequiredIids()); } - static Set<InstanceIdentifier<?>> aclHandledChildren(final InstanceIdentifier<Acl> parentId) { - return ImmutableSet.of(parentId.child(Ingress.class), - parentId.child(Ingress.class).child(VppAcls.class), - parentId.child(Egress.class), - parentId.child(Egress.class).child(VppAcls.class)); + static Set<InstanceIdentifier<?>> aclRequiredIids() { + return ImmutableSet.of(AclIIds.IFC, AclIIds.IFC_ACL, AclIIds.ACLS_ACL); } } diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/factory/VppAclWriterFactory.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/factory/VppAclWriterFactory.java deleted file mode 100644 index 883cf4f1f..000000000 --- a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/factory/VppAclWriterFactory.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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.hc2vpp.acl.write.factory; - -import static io.fd.hc2vpp.acl.write.factory.InterfaceAclWriterFactory.ACL_IID; -import static io.fd.hc2vpp.acl.write.factory.InterfaceAclWriterFactory.aclHandledChildren; - -import io.fd.hc2vpp.acl.util.factory.AclFactory; -import io.fd.hc2vpp.acl.write.VppAclCustomizer; -import io.fd.hc2vpp.acl.write.VppAclValidator; -import io.fd.honeycomb.translate.impl.write.GenericListWriter; -import io.fd.honeycomb.translate.write.WriterFactory; -import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder; -import javax.annotation.Nonnull; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.AccessLists; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - -public class VppAclWriterFactory extends AbstractAclWriterFactory implements WriterFactory, AclFactory { - - @Override - public void init(@Nonnull final ModifiableWriterRegistryBuilder registry) { - final InstanceIdentifier<AccessLists> rootNode = InstanceIdentifier.create(AccessLists.class); - - registry.subtreeAddBefore(vppAclChildren(InstanceIdentifier.create(Acl.class)), - new GenericListWriter<>(rootNode.child(Acl.class), - new VppAclCustomizer(futureAclFacade, standardAclContext, macIpAClContext), - new VppAclValidator() - ), - aclHandledChildren(ACL_IID)); - } -} diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/request/AclAddReplaceRequest.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/request/AclAddReplaceRequest.java new file mode 100644 index 000000000..29a7c7489 --- /dev/null +++ b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/request/AclAddReplaceRequest.java @@ -0,0 +1,132 @@ +/* + * 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.hc2vpp.acl.write.request; + +import io.fd.hc2vpp.acl.util.AclContextManager; +import io.fd.hc2vpp.acl.util.ace.AceConverter; +import io.fd.hc2vpp.acl.util.acl.AclDataExtractor; +import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.vpp.jvpp.acl.dto.AclAddReplace; +import io.fd.vpp.jvpp.acl.dto.AclAddReplaceReply; +import io.fd.vpp.jvpp.acl.dto.AclDel; +import io.fd.vpp.jvpp.acl.dto.MacipAclAdd; +import io.fd.vpp.jvpp.acl.dto.MacipAclAddReply; +import io.fd.vpp.jvpp.acl.dto.MacipAclDel; +import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade; +import java.util.List; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev181001.acls.Acl; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev181001.acls.acl.aces.Ace; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class AclAddReplaceRequest implements AclDataExtractor, AceConverter, JvppReplyConsumer { + + int ACL_INDEX_CREATE_NEW = -1; + private final FutureJVppAclFacade futureFacade; + private final MappingContext mappingContext; + + public AclAddReplaceRequest(@Nonnull final FutureJVppAclFacade futureFacade, + @Nonnull final MappingContext mappingContext) { + this.futureFacade = futureFacade; + this.mappingContext = mappingContext; + } + + + public void addStandardAcl(@Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl acl, + @Nonnull final AclContextManager standardAclContext) throws WriteFailedException { + + final AclAddReplace request = new AclAddReplace(); + + request.tag = getAclTag(acl); + request.aclIndex = ACL_INDEX_CREATE_NEW; + + final List<Ace> aces = getAces(acl); + request.r = toStandardAclRules(aces); + request.count = request.r.length; + + final AclAddReplaceReply reply = + getReplyForWrite(futureFacade.aclAddReplace(request).toCompletableFuture(), id); + + // maps new acl to returned index + standardAclContext.addAcl(reply.aclIndex, acl.getName(), aces, mappingContext); + } + + // according to vpp team, this was tested extensively, and should work + public void updateStandardAcl(@Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl acl, + @Nonnull final AclContextManager standardAclContext) throws WriteFailedException { + + final AclAddReplace request = new AclAddReplace(); + + request.tag = getAclTag(acl); + // by setting existing index, request is resolved as update + request.aclIndex = standardAclContext.getAclIndex(acl.getName(), mappingContext); + + final List<Ace> aces = getAces(acl); + request.r = toStandardAclRules(aces); + request.count = request.r.length; + + final AclAddReplaceReply reply = + getReplyForWrite(futureFacade.aclAddReplace(request).toCompletableFuture(), id); + + // overwrites existing acl metadata (aces might have been changed): + standardAclContext.addAcl(reply.aclIndex, acl.getName(), aces, mappingContext); + } + + public void deleteStandardAcl(@Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl acl, + @Nonnull final AclContextManager standardAclContext) throws WriteFailedException { + + final AclDel request = new AclDel(); + final String aclName = acl.getName(); + request.aclIndex = standardAclContext.getAclIndex(aclName, mappingContext); + + getReplyForDelete(futureFacade.aclDel(request).toCompletableFuture(), id); + + // removes mapping after successful delete + standardAclContext.removeAcl(aclName, mappingContext); + } + + public void addMacIpAcl(@Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl acl, + @Nonnull final AclContextManager macIpAclContext) throws WriteFailedException { + final MacipAclAdd request = new MacipAclAdd(); + + request.tag = getAclTag(acl); + + final List<Ace> aces = getAces(acl); + request.r = toMacIpAclRules(aces); + request.count = request.r.length; + + final MacipAclAddReply reply = getReplyForWrite(futureFacade.macipAclAdd(request).toCompletableFuture(), id); + + // map mac-ip acl to returned index + macIpAclContext.addAcl(reply.aclIndex, acl.getName(), aces, mappingContext); + } + + public void deleteMacIpAcl(@Nonnull final InstanceIdentifier<Acl> id, @Nonnull final Acl acl, + @Nonnull final AclContextManager macIpAclContext) throws WriteFailedException { + final MacipAclDel request = new MacipAclDel(); + final String aclName = acl.getName(); + request.aclIndex = macIpAclContext.getAclIndex(aclName, mappingContext); + + getReplyForDelete(futureFacade.macipAclDel(request).toCompletableFuture(), id); + + macIpAclContext.removeAcl(aclName, mappingContext); + } + + +} diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/request/AclInterfaceAssignmentRequest.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/request/AclInterfaceAssignmentRequest.java new file mode 100644 index 000000000..2d7777e35 --- /dev/null +++ b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/request/AclInterfaceAssignmentRequest.java @@ -0,0 +1,172 @@ +/* + * 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.hc2vpp.acl.write.request; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.collect.ImmutableList; +import io.fd.hc2vpp.acl.util.AclContextManager; +import io.fd.hc2vpp.common.translate.util.ByteDataTranslator; +import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.vpp.jvpp.acl.dto.AclInterfaceSetAclList; +import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade; +import java.util.Collections; +import java.util.List; +import java.util.stream.Stream; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev181001.acls.attachment.points.Interface; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Multi-assignment single-request taking advantage from acl_interface_set_acl_list api + */ +public class AclInterfaceAssignmentRequest implements JvppReplyConsumer, ByteDataTranslator { + + private static final Logger LOG = LoggerFactory.getLogger(AclInterfaceAssignmentRequest.class); + + private final MappingContext mappingContext; + private InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev181001.acls.attachment.points.Interface> + identifier; + private List<String> inputAclNames = Collections.emptyList(); + private List<String> outputAclNames = Collections.emptyList(); + private AclContextManager standardAclContext; + private NamingContext interfaceContext; + + + private AclInterfaceAssignmentRequest(final MappingContext mappingContext) { + this.mappingContext = checkNotNull(mappingContext, "Mapping context cannot be null"); + } + + public static AclInterfaceAssignmentRequest create(@Nonnull final MappingContext mappingContext) { + return new AclInterfaceAssignmentRequest(mappingContext); + } + + public AclInterfaceAssignmentRequest identifier( + @Nonnull final InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev181001.acls.attachment.points.Interface> identifier) { + this.identifier = identifier; + return this; + } + + public AclInterfaceAssignmentRequest inputAclNames(@Nonnull final List<String> inputAclNames) { + checkNotNull(inputAclNames, "Input ACL names cannot be null"); + this.inputAclNames = ImmutableList.copyOf(inputAclNames); + return this; + } + + public AclInterfaceAssignmentRequest outputAclNames(@Nonnull final List<String> outputAclNames) { + checkNotNull(outputAclNames, "Output ACL names cannot be null"); + this.outputAclNames = ImmutableList.copyOf(outputAclNames); + return this; + } + + public AclInterfaceAssignmentRequest standardAclContext(@Nonnull final AclContextManager standardAclContext) { + this.standardAclContext = standardAclContext; + return this; + } + + public AclInterfaceAssignmentRequest interfaceContext(@Nonnull final NamingContext interfaceContext) { + this.interfaceContext = interfaceContext; + return this; + } + + private void checkValidRequest() { + checkNotNull(identifier, "Identifier cannot be null"); + checkNotNull(standardAclContext, "ACL context cannot be null"); + checkNotNull(interfaceContext, "Interface context cannot be null"); + } + + public void executeAsCreate(@Nonnull final FutureJVppAclFacade api) throws WriteFailedException { + checkValidRequest(); + final String interfaceName = identifier.firstKeyOf(Interface.class).getInterfaceId(); + + // locking on mapping context, to prevent modifying of mappings (for both contexts) during binding/execution of request + synchronized (mappingContext) { + LOG.debug( + "Executing acl interface assignment write request for interface={}, input ACL's={},output ACL's={}", + interfaceName, inputAclNames, outputAclNames); + + getReplyForWrite(api.aclInterfaceSetAclList(createRequest(interfaceName)).toCompletableFuture(), + identifier); + LOG.debug( + "Acl interface assignment write request for interface={}, input ACL's={},output ACL's={} successfully passed", + interfaceName, inputAclNames, outputAclNames); + } + } + + public void executeAsUpdate(@Nonnull final FutureJVppAclFacade api, + final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev181001.acls.attachment.points.Interface before, + final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev181001.acls.attachment.points.Interface after) + throws WriteFailedException { + checkValidRequest(); + final String interfaceName = identifier.firstKeyOf(Interface.class).getInterfaceId(); + + // locking on mapping context, to prevent modifying of mappings (for both contexts) during binding/execution of request + synchronized (mappingContext) { + LOG.debug( + "Executing acl interface assignment update request for interface={}, input ACL's={},output ACL's={}", + interfaceName, inputAclNames, outputAclNames); + + getReplyForUpdate(api.aclInterfaceSetAclList(createRequest(interfaceName)).toCompletableFuture(), + identifier, before, after); + LOG.debug( + "Acl interface assignment update request for interface={}, input ACL's={},output ACL's={} successfully passed", + interfaceName, inputAclNames, outputAclNames); + } + } + + public void executeAsDelete(@Nonnull final FutureJVppAclFacade api) throws WriteFailedException { + checkValidRequest(); + final String interfaceName = identifier.firstKeyOf(Interface.class).getInterfaceId(); + + // locking on mapping context, to prevent modifying of mappings (for both contexts) during binding/execution of request + synchronized (mappingContext) { + LOG.debug( + "Executing acl interface assignment delete request for interface={}, input ACL's={},output ACL's={}", + interfaceName, inputAclNames, outputAclNames); + + // remove all ACLs, just in case they were set by AclInterfaceAssignmentRequest user + inputAclNames = Collections.emptyList(); + outputAclNames = Collections.emptyList(); + + getReplyForDelete(api.aclInterfaceSetAclList(createRequest(interfaceName)).toCompletableFuture(), + identifier); + LOG.debug( + "Acl interface assignment delete request for interface={}, input ACL's={},output ACL's={} successfully passed", + interfaceName, inputAclNames, outputAclNames); + } + } + + // synchronized on higher layer + private AclInterfaceSetAclList createRequest(final String interfaceName) { + + AclInterfaceSetAclList request = new AclInterfaceSetAclList(); + request.swIfIndex = interfaceContext.getIndex(interfaceName, mappingContext); + // FIXME (HC2VPP-201): possible overflow + request.nInput = (byte) inputAclNames.size(); + request.count = (byte) (inputAclNames.size() + outputAclNames.size()); + request.acls = Stream.concat(inputAclNames.stream(), outputAclNames.stream()) + .mapToInt(aclName -> standardAclContext.getAclIndex(aclName, mappingContext)) + .toArray(); + return request; + } +} diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/request/MacIpInterfaceAssignmentRequest.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/request/MacIpInterfaceAssignmentRequest.java new file mode 100644 index 000000000..b7849991b --- /dev/null +++ b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/request/MacIpInterfaceAssignmentRequest.java @@ -0,0 +1,113 @@ +/* + * 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.hc2vpp.acl.write.request; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.hc2vpp.acl.util.AclContextManager; +import io.fd.hc2vpp.common.translate.util.ByteDataTranslator; +import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.vpp.jvpp.acl.dto.MacipAclInterfaceAddDel; +import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev181001.acls.attachment.points.Interface; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MacIpInterfaceAssignmentRequest implements ByteDataTranslator, JvppReplyConsumer { + + private static final Logger LOG = LoggerFactory.getLogger(MacIpInterfaceAssignmentRequest.class); + + private final boolean isNew; + private final MappingContext mappingContext; + private InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev181001.acls.attachment.points.Interface> + identifier; + private String aclName; + private AclContextManager macIpAclContext; + private NamingContext interfaceContext; + + + private MacIpInterfaceAssignmentRequest(final boolean isNew, final MappingContext mappingContext) { + this.isNew = isNew; + this.mappingContext = checkNotNull(mappingContext, "Mapping context cannot be null"); + } + + public static MacIpInterfaceAssignmentRequest addNew(@Nonnull final MappingContext mappingContext) { + return new MacIpInterfaceAssignmentRequest(true, mappingContext); + } + + public static MacIpInterfaceAssignmentRequest deleteExisting(@Nonnull final MappingContext mappingContext) { + return new MacIpInterfaceAssignmentRequest(false, mappingContext); + } + + public MacIpInterfaceAssignmentRequest identifier( + @Nonnull final InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev181001.acls.attachment.points.Interface> identifier) { + this.identifier = identifier; + return this; + } + + public MacIpInterfaceAssignmentRequest aclName(@Nonnull final String aclName) { + this.aclName = aclName; + return this; + } + + public MacIpInterfaceAssignmentRequest macIpAclContext(@Nonnull final AclContextManager macIpAclContext) { + this.macIpAclContext = macIpAclContext; + return this; + } + + public MacIpInterfaceAssignmentRequest interfaceContext(@Nonnull final NamingContext interfaceContext) { + this.interfaceContext = interfaceContext; + return this; + } + + private void checkValidRequest() { + checkNotNull(identifier, "Identifier cannot be null"); + checkNotNull(aclName, "ACL name cannot be null"); + checkNotNull(macIpAclContext, "ACL context cannot be null"); + checkNotNull(interfaceContext, "Interface context cannot be null"); + } + + public void execute(@Nonnull final FutureJVppAclFacade api) + throws WriteFailedException { + + // locking on mapping context, to prevent modifying of mappings (for both contexts) during execution of request + synchronized (mappingContext) { + checkValidRequest(); + + final String interfaceName = identifier.firstKeyOf(Interface.class).getInterfaceId(); + + MacipAclInterfaceAddDel request = new MacipAclInterfaceAddDel(); + request.isAdd = booleanToByte(isNew); + request.aclIndex = macIpAclContext.getAclIndex(aclName, mappingContext); + request.swIfIndex = + interfaceContext.getIndex(interfaceName, mappingContext); + + LOG.debug("Executing mac-ip interface assignment request for isNew={},aclName={},interfaceName={}", isNew, + aclName, interfaceName); + getReplyForWrite(api.macipAclInterfaceAddDel(request).toCompletableFuture(), identifier); + LOG.debug( + "Mac-ip interface assignment request for isNew={},aclName={},interfaceName={} successfully passed", + isNew, aclName, interfaceName); + } + } +} |