Upgrading ACL implementation 70/62770/16
authorTomas Cechvala <tcechval@cisco.com>
Wed, 6 Sep 2017 14:13:16 +0000 (16:13 +0200)
committerMichal Cmarada <mcmarada@cisco.com>
Tue, 3 Oct 2017 07:44:52 +0000 (07:44 +0000)
Only DHCP peers from a local network are configured in ACLs.
Deltas are computed to update specific rules to avoid rewriting
entire ACLs.

Change-Id: I9245c9ab961a1090d1d0d04ead937b78f789f3bf
Signed-off-by: Tomas Cechvala <tcechval@cisco.com>
renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/iface/InterfaceManager.java
renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/policy/ForwardingManager.java
renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/policy/VppRendererPolicyManager.java
renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/policy/acl/AccessListUtil.java
renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/policy/acl/AclManager.java
renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/policy/acl/AddressMapper.java
renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/policy/acl/GbpAceBuilder.java
renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/sf/EtherTypeClassifier.java
renderers/vpp/src/main/java/org/opendaylight/groupbasedpolicy/renderer/vpp/util/KeyFactory.java
renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/policy/acl/AclManagerTest.java
renderers/vpp/src/test/java/org/opendaylight/groupbasedpolicy/renderer/vpp/policy/acl/TestResources.java

index 14bc6978dbb34cb7ebe1692d82cf47fa70c79694..5444208d0c92716bd3e29f96721807f36495d340 100644 (file)
@@ -37,7 +37,6 @@ import org.opendaylight.groupbasedpolicy.renderer.vpp.util.VppRendererProcessing
 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
 import org.opendaylight.vbd.impl.transaction.VbdNetconfTransaction;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.absolute.location.LocationType;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.absolute.location.location.type.ExternalLocationCase;
@@ -68,10 +67,9 @@ import com.google.common.base.Strings;
 import com.google.common.collect.HashMultimap;
 import com.google.common.collect.SetMultimap;
 import com.google.common.eventbus.Subscribe;
-import com.google.common.util.concurrent.MoreExecutors;
-import com.google.common.util.concurrent.AsyncFunction;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
 
 public class InterfaceManager implements AutoCloseable {
 
index 574d9393777b8ab1960a03680f1e78ace7c7de36..eaa16e67bf1ca881f8fca075152f3a273fc8eac3 100644 (file)
@@ -259,7 +259,6 @@ public final class ForwardingManager {
                     LOG.warn("Interface was not added to bridge-domain {} for endpoint {}", l2FloodDomain, rEp, e);
                 }
             }
-            aclManager.updateAclsForPeers(policyCtx, rEpKey);
         } else {
             LOG.debug("Forwarding is not created - Location of renderer endpoint contains "
                     + "external-node therefore VPP renderer assumes that interface for endpoint is "
index 650cb385f42fb40e940dc135027de4e427fdb989..05a8ae183479988dc1c4ae886e76456f190add43 100644 (file)
@@ -27,8 +27,10 @@ import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.DhcpRelayCommand;
 import org.opendaylight.groupbasedpolicy.renderer.vpp.config.ConfigUtil;
 import org.opendaylight.groupbasedpolicy.renderer.vpp.event.NodeOperEvent;
 import org.opendaylight.groupbasedpolicy.renderer.vpp.event.RendererPolicyConfEvent;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.policy.acl.AccessListWrapper;
 import org.opendaylight.groupbasedpolicy.renderer.vpp.policy.acl.AclManager;
 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.KeyFactory;
+import org.opendaylight.groupbasedpolicy.renderer.vpp.util.VppIidFactory;
 import org.opendaylight.groupbasedpolicy.util.IidFactory;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.absolute.location.location.type.ExternalLocationCase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.RendererPolicy;
@@ -153,7 +155,7 @@ public class VppRendererPolicyManager {
         ImmutableSet<RendererEndpointKey> rendEpsAfter = policyCtxAfter.getPolicyTable().rowKeySet();
 
         SetView<RendererEndpointKey> removedRendEps = Sets.difference(rendEpsBefore, rendEpsAfter);
-        removedRendEps.forEach(rEpKey -> fwManager.removeForwardingForEndpoint(rEpKey, policyCtxBefore));
+        removedRendEps.forEach(rEpKey -> fwManager.removeForwardingForEndpoint(rEpKey, policyCtxBefore));//TODO
 
         if (!ConfigUtil.getInstance().isL3FlatEnabled()) {
             LOG.debug("Removing bridge domains on nodes {}", removedVppNodesByL2Fd);
@@ -190,7 +192,7 @@ public class VppRendererPolicyManager {
         fwManager.syncRouting(policyCtxAfter);
 
         SetView<RendererEndpointKey> createdRendEps = Sets.difference(rendEpsAfter, rendEpsBefore);
-        createdRendEps.forEach(rEpKey -> fwManager.createForwardingForEndpoint(rEpKey, policyCtxAfter));
+        createdRendEps.forEach(rEpKey -> fwManager.createForwardingForEndpoint(rEpKey, policyCtxAfter));//TODO
 
         SetView<RendererEndpointKey> updatedRendEps = Sets.intersection(rendEpsBefore, rendEpsAfter);
         // update forwarding for endpoint
@@ -259,6 +261,14 @@ public class VppRendererPolicyManager {
         rEpKeys.forEach(rEpKey -> fwManager.createForwardingForEndpoint(rEpKey, policyCtx));
         fwManager.createNatEntries(policyCtx);
         fwManager.syncRouting(policyCtx);
+
+        ImmutableSet<RendererEndpointKey> rendEpsAfter = policyCtx.getPolicyTable().rowKeySet();
+        ImmutableSet<RuleGroupKey> rulesAfter = policyCtx.getRuleGroupByKey().keySet();
+        LOG.info("rendererPolicyCreated Created rules {}", rulesAfter);
+        LOG.info("rendererPolicyCreated Created renderer endpoints {}", rendEpsAfter);
+        aclManager.resolveRulesToConfigure(policyCtx, Sets.difference(rendEpsAfter, Sets.newHashSet()),
+                Sets.difference(rulesAfter, Sets.newHashSet()), true);
+
     }
 
     private void rendererPolicyDeleted(RendererPolicy rendererPolicy) {
@@ -278,6 +288,14 @@ public class VppRendererPolicyManager {
         }
         fwManager.deleteNatEntries(policyCtx);
         fwManager.deleteRouting(policyCtx);
+
+        ImmutableSet<RendererEndpointKey> rendEpsBefore = policyCtx.getPolicyTable().rowKeySet();
+        ImmutableSet<RuleGroupKey> rulesBefore = policyCtx.getRuleGroupByKey().keySet();
+        LOG.debug("rendererPolicyDeleted. Removed rules {}", rulesBefore);
+        LOG.debug("rendererPolicyDeleted. Endpoints deleted {}", rendEpsBefore);
+        aclManager.resolveRulesToConfigure(policyCtx, Sets.difference(rendEpsBefore, Sets.newHashSet()),
+                Sets.difference(rulesBefore, Sets.newHashSet()), false);
+
     }
 
     private static SetMultimap<String, NodeId> resolveVppNodesByL2Fd(Set<RendererEndpointKey> rEpKeys,
index 8a84f497180d11e8fafc433b80864395e513a64a..2d927d9601a83e2f1032cdd207501defa121f8c3 100644 (file)
@@ -80,15 +80,16 @@ public class AccessListUtil {
             .stream()
             .filter(peerEpKey -> peerHasLocation(ctx, peerEpKey))
             .forEach(peerEpKey -> {
+                List<GbpAceBuilder> rules = new ArrayList<>();
                 ctx.getPolicyTable().get(rEpKey, peerEpKey).forEach(resolvedRules -> {
-                    List<GbpAceBuilder> rules = new ArrayList<>();
                     Direction classifDir = calculateClassifDirection(resolvedRules.getRendererEndpointParticipation(),
                             policyDirection);
                     rules.addAll(resolveAclRulesFromPolicy(resolvedRules, classifDir, rEpKey, peerEpKey));
-                    updateAddressesInRules(rules, rEpKey, peerEpKey, ctx, policyDirection, true);
-                    aclWrapper.writeRules(rules);
 
                 });
+                if (validateAndUpdateAddressesInRules(rules, rEpKey, peerEpKey, ctx, policyDirection, true)) {
+                    aclWrapper.writeRules(rules);
+                }
             });
     }
 
@@ -126,16 +127,20 @@ public class AccessListUtil {
         return Direction.In;
     }
 
-    static void updateAddressesInRules(List<GbpAceBuilder> rules, RendererEndpointKey rEpKey, PeerEndpointKey peerEpKey,
-            PolicyContext ctx, ACE_DIRECTION policyDirection, boolean resolveForLocationPeers) {
+    static boolean validateAndUpdateAddressesInRules(List<GbpAceBuilder> rules, RendererEndpointKey rEpKey,
+            PeerEndpointKey peerEpKey, PolicyContext ctx, ACE_DIRECTION policyDirection,
+            boolean resolveForLocationPeers) {
         for (AddressMapper addrMapper : Arrays.asList(new SourceMapper(policyDirection),
                 new DestinationMapper(policyDirection))) {
             if (peerHasLocation(ctx, peerEpKey) && resolveForLocationPeers) {
-                addrMapper.updateRules(rules, findAddrEp(ctx, rEpKey), findAddrEp(ctx, peerEpKey));
+                if (!addrMapper.updateRules(rules, findAddrEp(ctx, rEpKey), findAddrEp(ctx, peerEpKey))) {
+                    return false;
+                }
             } else if (!peerHasLocation(ctx, peerEpKey) && !resolveForLocationPeers) {
                 addrMapper.updateExtRules(rules, findAddrEp(ctx, rEpKey), null);
             }
         }
+        return true;
     }
 
     private static boolean peerHasLocation(PolicyContext ctx, PeerEndpointKey peerEpKey) {
@@ -318,8 +323,7 @@ public class AccessListUtil {
     }
 
     static void setSourceL3Address(GbpAceBuilder rule, String address) throws UnknownHostException {
-        InetAddress addr = InetAddress.getByName(substringBeforeSlash(address));
-        if (addr instanceof Inet6Address) {
+        if (isIpv6Address(address)) {
             rule.setIpAddresses(new Ipv6Prefix(address), null);
         } else {
             rule.setIpAddresses(new Ipv4Prefix(address), null);
@@ -327,14 +331,23 @@ public class AccessListUtil {
     }
 
     static void setDestinationL3Address(GbpAceBuilder rule, String address) throws UnknownHostException {
-        InetAddress addr = InetAddress.getByName(substringBeforeSlash(address));
-        if (addr instanceof Inet6Address) {
+        if (isIpv6Address(address)) {
             rule.setIpAddresses(null, new Ipv6Prefix(address));
         } else {
             rule.setIpAddresses(null, new Ipv4Prefix(address));
         }
     }
 
+    public static boolean isIpv4Address(String address) throws UnknownHostException {
+        InetAddress addr = InetAddress.getByName(substringBeforeSlash(address));
+        return addr instanceof Inet4Address;
+    }
+
+    public static boolean isIpv6Address(String address) throws UnknownHostException {
+        InetAddress addr = InetAddress.getByName(substringBeforeSlash(address));
+        return addr instanceof Inet6Address;
+    }
+
     static GbpAceBuilder denyIngressTrafficForPrefix(Subnet subnet) {
         IpPrefix ipPrefix = subnet.getIpPrefix();
         if (ipPrefix.getIpv4Prefix() != null) {
index 05e04f1798811d52ad13fc0c5c4bbe5e3c7ce541..9b4f4f5f3853102e70a045f654bcf832446e8cdd 100644 (file)
@@ -197,40 +197,60 @@ public class AclManager {
         };
         beans.forEach(bean -> {
             List<GbpAceBuilder> aceBuilders = bean.resolveAces(resolveUpdates(policyCtx, bean.epKey, bean.ruleGroups));
-            getInterfacesForEndpoint(policyCtx, KeyFactory.addressEndpointKey(bean.epKey)).asMap()
+            resolveInterfaces(KeyFactory.addressEndpointKey(bean.epKey), policyCtx).asMap()
                 .forEach((nodeId, intfcs) -> {
-                    intfcs.stream()
-                        .filter(intf -> !interfaceManager.isExcludedFromPolicy(nodeId, getIntfName.apply(intf)))
-                        .forEach(intf -> {
-                            AclKey aclKey = new AclKey(getIntfName.apply(intf) + bean.aceDirection, VppAcl.class);
-                            denyTenantTraffic.put(nodeId, aclKey,
-                                    getWorkaroundFlows(policyCtx, bean.epKey, bean.aceDirection));
-                            AccessListUtil.allowExternalNetworksForEp(bean.epKey, bean.aceDirection).build();
-                            denyTenantTraffic.put(nodeId, aclKey,
-                                    AccessListUtil.denyDomainSubnets(policyCtx, bean.aceDirection)
-                                        .stream()
-                                        .map(GbpAceBuilder::build)
-                                        .collect(Collectors.toList()));
-                            permitExternal.put(nodeId, aclKey, Lists.newArrayList(
-                                    AccessListUtil.allowExternalNetworksForEp(bean.epKey, bean.aceDirection).build()));
-                            Optional<List<Ace>> entries = Optional.fromNullable(aceTable.get(nodeId, aclKey));
-                            aceTable.put(nodeId, aclKey,
-                                    Stream
-                                        .concat((entries.isPresent()) ? entries.get().stream() : Stream.empty(),
-                                                aceBuilders.stream().map(aceBuilder -> aceBuilder.build()))
-                                        .collect(Collectors.toList()));
-                        });
+                    intfcs.stream().forEach(intf -> {
+                        if (!write && changedEndpoints.contains(bean.epKey)) {
+                            AccessListWrapper.removeAclsForInterface(VppIidFactory.getNetconfNodeIid(nodeId), intf);
+                            return;
+                        }
+                        AclKey aclKey = new AclKey(getIntfName.apply(intf) + bean.aceDirection, VppAcl.class);
+                        denyTenantTraffic.put(nodeId, aclKey,
+                                getWorkaroundFlows(policyCtx, bean.epKey, bean.aceDirection));
+                        AccessListUtil.allowExternalNetworksForEp(bean.epKey, bean.aceDirection).build();
+                        denyTenantTraffic.put(nodeId, aclKey,
+                                AccessListUtil.denyDomainSubnets(policyCtx, bean.aceDirection)
+                                    .stream()
+                                    .map(GbpAceBuilder::build)
+                                    .collect(Collectors.toList()));
+                        permitExternal.put(nodeId, aclKey, Lists.newArrayList(
+                                AccessListUtil.allowExternalNetworksForEp(bean.epKey, bean.aceDirection).build()));
+                        Optional<List<Ace>> entries = Optional.fromNullable(aceTable.get(nodeId, aclKey));
+                        aceTable.put(nodeId, aclKey,
+                                Stream
+                                    .concat((entries.isPresent()) ? entries.get().stream() : Stream.empty(),
+                                            aceBuilders.stream().map(aceBuilder -> aceBuilder.build()))
+                                    .collect(Collectors.toList()));
+                    });
                 });
         });
-        // to avoid empty ACL (IllegalStateArgument on HC), rules have to be updated gently
         updateRules(ImmutableTable.copyOf(aceTable), write);
-        updateRules(ImmutableTable.copyOf(denyTenantTraffic), false);
-        updateRules(ImmutableTable.copyOf(denyTenantTraffic), true);
-        updateRules(ImmutableTable.copyOf(permitExternal), false);
-        updateRules(ImmutableTable.copyOf(permitExternal), true);
+        if (write) {
+            // to avoid empty ACL (IllegalStateArgument on HC), rules have to be updated gently
+            updateRules(ImmutableTable.copyOf(denyTenantTraffic), false);
+            updateRules(ImmutableTable.copyOf(denyTenantTraffic), true);
+            updateRules(ImmutableTable.copyOf(permitExternal), false);
+            updateRules(ImmutableTable.copyOf(permitExternal), true);
+        }
 
     }
 
+    public ImmutableSetMultimap<NodeId, InterfaceKey> resolveInterfaces(AddressEndpointKey key,
+            PolicyContext policyCtx) {
+        Function<InterfaceKey, String> getIntfName = (intf) -> {
+            Optional<String> intfName = VppPathMapper.interfacePathToInterfaceName(intf.getName());
+            Preconditions.checkArgument(intfName.isPresent(), "Failed to resolve interface name from " + intf);
+            return intfName.get();
+        };
+        SetMultimap<NodeId, InterfaceKey> result = HashMultimap.create();
+        getInterfacesForEndpoint(policyCtx, key).forEach((nodeId, intf) -> {
+            if (!interfaceManager.isExcludedFromPolicy(nodeId, getIntfName.apply(intf))) {
+                result.put(nodeId, intf);
+            }
+        });
+        return ImmutableSetMultimap.copyOf(result);
+    }
+
     private List<Ace> getWorkaroundFlows(PolicyContext policyCtx, RendererEndpointKey key, ACE_DIRECTION dir) {
         List<Ace> result = new ArrayList<>();
         result.addAll(AccessListUtil.denyDomainSubnets(policyCtx, dir)
@@ -248,8 +268,8 @@ public class AclManager {
         rendEp.get()
             .getPeerEndpoint()
             .stream()
-            // TODO see UT
             .filter(peerEp -> policyCtx.getPolicyTable().get(rendEpKey, peerEp.getKey()) != null)
+            .filter(peerEp -> !endpointIsExcludedFromPolicy(policyCtx, KeyFactory.addressEndpointKey(peerEp.getKey())))
             .forEach(peerEp -> {
                 updateTreeBuilder.put(rendEpKey, peerEp.getKey(),
                         policyCtx.getPolicyTable()
@@ -261,6 +281,13 @@ public class AclManager {
         return updateTreeBuilder.build();
     }
 
+    private boolean endpointIsExcludedFromPolicy(PolicyContext policyCtx, AddressEndpointKey key) {
+        return getInterfacesForEndpoint(policyCtx, key).entries().stream().anyMatch(entry -> {
+            Optional<String> intfName = VppPathMapper.interfacePathToInterfaceName(entry.getValue().getName());
+            return intfName.isPresent() ? interfaceManager.isExcludedFromPolicy(entry.getKey(), intfName.get()) : false;
+        });
+    }
+
     private void updateRules(ImmutableTable<NodeId, AclKey, List<Ace>> rulesToUpdate, boolean write) {
         List<ListenableFuture<Void>> sync = new ArrayList<>();
         rulesToUpdate.rowKeySet().forEach(nodeId -> {
@@ -269,8 +296,7 @@ public class AclManager {
                 @Override
                 public Void call() throws Exception {
                     InstanceIdentifier<Node> vppIid = VppIidFactory.getNetconfNodeIid(nodeId);
-                    Optional<DataBroker> dataBroker =
-                        mountDataProvider.resolveDataBrokerForMountPoint(vppIid);
+                    Optional<DataBroker> dataBroker = mountDataProvider.resolveDataBrokerForMountPoint(vppIid);
                     if (!dataBroker.isPresent()) {
                         LOG.error("Failed to update ACLs for endpoints on node {}. Mount point does not exist.",
                                 nodeId);
@@ -285,6 +311,7 @@ public class AclManager {
                                 .child(Ace.class, ace.getKey())
                                 .build(), ace);
                         });
+                        LOG.debug("Writing ACE changes - Node: {} Entries: {}", nodeId, entries);
                         if (entries.isEmpty()) {
                             return;
                         }
@@ -310,39 +337,22 @@ public class AclManager {
     }
 
     private List<GbpAceBuilder> generateRulesForEndpointPair(PolicyContext ctx, RendererEndpointKey r,
-            PeerEndpointKey p, RendererResolvedPolicy rrp, ACE_DIRECTION aceDirection) {
+            PeerEndpointKey p, List<RendererResolvedPolicy> rrps, ACE_DIRECTION aceDirection) {
         List<GbpAceBuilder> rules = new ArrayList<>();
-        Direction direction =
-                AccessListUtil.calculateClassifDirection(rrp.getRendererEndpointParticipation(), aceDirection);
-        ResolvedRuleGroup resolvedRuleGroup = ctx.getRuleGroupByKey().get(rrp.getRuleGroup().getRelatedRuleGroupKey());
-        resolvedRuleGroup.getRules().forEach(rule -> {
-            Optional<GbpAceBuilder> ace = AccessListUtil.resolveAceClassifersAndAction(rule, direction,
-                    AccessListUtil.resolveAceName(rule.getName(), r, p));
-            if (ace.isPresent()) {
-                rules.add(ace.get());
-            }
-        });
-        AccessListUtil.updateAddressesInRules(rules, r, p, ctx, aceDirection, true);
-        return rules;
-    }
-
-    // TODO remove
-    public void updateAclsForPeers(PolicyContext policyCtx, RendererEndpointKey rEpKey) {
-        ImmutableSet<PeerEndpointKey> peers = policyCtx.getPolicyTable().row(rEpKey).keySet();
-        List<ListenableFuture<Void>> sync = new ArrayList<>();
-        for (RendererEndpointKey peerRendEp : peers.stream()
-            .map(AddressEndpointUtils::fromPeerEpKey)
-            .collect(Collectors.toList())
-            .stream()
-            .map(AddressEndpointUtils::toRendererEpKey)
-            .collect(Collectors.toList())) {
-            sync.add(updateAclsForRendEp(peerRendEp, policyCtx));
-        }
-        try {
-            Futures.allAsList(sync).get();
-        } catch (InterruptedException | ExecutionException e) {
-            LOG.error("Failed to update ACLs for peers of {}. {}", rEpKey, e);
+        for (RendererResolvedPolicy rrp : rrps) {
+            Direction direction =
+                    AccessListUtil.calculateClassifDirection(rrp.getRendererEndpointParticipation(), aceDirection);
+            ResolvedRuleGroup resolvedRuleGroup =
+                    ctx.getRuleGroupByKey().get(rrp.getRuleGroup().getRelatedRuleGroupKey());
+            resolvedRuleGroup.getRules().forEach(rule -> {
+                Optional<GbpAceBuilder> ace = AccessListUtil.resolveAceClassifersAndAction(rule, direction,
+                        AccessListUtil.resolveAceName(rule.getName(), r, p));
+                if (ace.isPresent()) {
+                    rules.add(ace.get());
+                }
+            });
         }
+        return rules;
     }
 
     public ListenableFuture<Void> updateAclsForRendEp(RendererEndpointKey rEpKey, PolicyContext policyCtx) {
@@ -486,19 +496,34 @@ public class AclManager {
 
         List<GbpAceBuilder> resolveAces(
                 ImmutableTable<RendererEndpointKey, PeerEndpointKey, List<RendererResolvedPolicy>> updateTree) {
+            return (write) ? resolveCreatedAces(updateTree) : resolveRemovedAces(updateTree);
+        }
+
+        List<GbpAceBuilder> resolveCreatedAces(
+                ImmutableTable<RendererEndpointKey, PeerEndpointKey, List<RendererResolvedPolicy>> updateTree) {
             List<GbpAceBuilder> result = new ArrayList<>();
             updateTree.columnKeySet().stream().filter(peer -> updateTree.get(epKey, peer) != null).forEach(peer -> {
+                List<GbpAceBuilder> deltaRules =
+                        generateRulesForEndpointPair(policyCtx, epKey, peer, updateTree.get(epKey, peer), aceDirection);
+                if (AccessListUtil.validateAndUpdateAddressesInRules(deltaRules, epKey, peer, policyCtx, aceDirection,
+                        true)) {
+                    result.addAll(deltaRules);
+                }
+            });
+            return result;
+        }
+
+        List<GbpAceBuilder> resolveRemovedAces(
+                ImmutableTable<RendererEndpointKey, PeerEndpointKey, List<RendererResolvedPolicy>> updateTree) {
+            List<GbpAceBuilder> result = new ArrayList<>();
+            updateTree.columnKeySet().stream().filter(peer -> updateTree.get(epKey, peer) != null).forEach(peer -> {
+                // we only need to resolve rule names when removing ACE
                 updateTree.get(epKey, peer).stream().forEach(rrp -> {
-                    if (write) {
-                        result.addAll(generateRulesForEndpointPair(policyCtx, epKey, peer, rrp, aceDirection));
-                    } else {
-                        // we only need to resolve rule names when removing ACE
-                        result.addAll(rrp.getRuleGroup()
-                            .getRules()
-                            .stream()
-                            .map(rule -> new GbpAceBuilder(AccessListUtil.resolveAceName(rule.getName(), epKey, peer)))
-                            .collect(Collectors.toList()));
-                    }
+                    result.addAll(rrp.getRuleGroup()
+                        .getRules()
+                        .stream()
+                        .map(rule -> new GbpAceBuilder(AccessListUtil.resolveAceName(rule.getName(), epKey, peer)))
+                        .collect(Collectors.toList()));
                 });
             });
             return result;
index 8d42237db05b4f0a37186af7e3842c9129a2b521..f84e05fceb912eccf9d18a43f2db95d06c0b85d3 100644 (file)
@@ -8,23 +8,41 @@
 
 package org.opendaylight.groupbasedpolicy.renderer.vpp.policy.acl;
 
+import java.net.UnknownHostException;
+import java.util.ArrayList;
 import java.util.List;
+import java.util.stream.Collectors;
 
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.acl.transport.header.fields.DestinationPortRangeBuilder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.acl.transport.header.fields.SourcePortRangeBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.containment.endpoints.ContainmentEndpoint;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev170511.IpPrefixType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev170511.L2BridgeDomain;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev170511.L3Context;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev170511.MacAddressType;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.endpoints.AddressEndpointWithLocation;
+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.vpp.ace.vpp.ace.nodes.ace.ip.version.AceIpv4;
+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.vpp.ace.vpp.ace.nodes.ace.ip.version.AceIpv6;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableMap;
 
 
 abstract class AddressMapper {
 
+    private static final Logger LOG = LoggerFactory.getLogger(AddressMapper.class);
+
     private AccessListUtil.ACE_DIRECTION direction;
 
     private static final PortNumber DHCP_67 = new PortNumber(67);
     private static final PortNumber DHCP_68 = new PortNumber(68);
     private static final PortNumber DHCPV6_547 = new PortNumber(547);
     private static final PortNumber DHCPV6_548 = new PortNumber(548);
+    private static final ImmutableMap<PortNumber, PortNumber> dhcpSockets =
+            ImmutableMap.of(DHCP_67, DHCP_68, DHCP_68, DHCP_67, DHCPV6_548, DHCPV6_547, DHCPV6_547, DHCPV6_548);
 
     AddressMapper(AccessListUtil.ACE_DIRECTION direction) {
         this.direction = direction;
@@ -36,55 +54,104 @@ abstract class AddressMapper {
     abstract List<GbpAceBuilder> updateExtRules(List<GbpAceBuilder> rules, AddressEndpointWithLocation localEp,
             ContainmentEndpoint cEp);
 
-    public List<GbpAceBuilder> updateRules(List<GbpAceBuilder> rules, AddressEndpointWithLocation localEp,
+    public boolean updateRules(List<GbpAceBuilder> rules, AddressEndpointWithLocation localEp,
             AddressEndpointWithLocation peerEp) {
-        if (this instanceof SourceMapper) {
-            if (AccessListUtil.ACE_DIRECTION.INGRESS.equals(direction)) {
-                return updateRules(rules, localEp);
+        filterRulesWithIrrelevantAddresses(rules, localEp, peerEp);
+        for (GbpAceBuilder rule : rules) {
+            LOG.info("Rule: {} Updating rule between {} and {}. Start.", rule, localEp.getAddress(),
+                    peerEp.getAddress());
+            boolean isDhcpRule = dhcpSockets.entrySet().stream().anyMatch(dhcpSocket -> {
+                boolean srcMatch = isInRange(rule.getSourcePortRangeBuilder(), dhcpSocket.getKey());
+                boolean dstMatch = isInRange(rule.getDestinationPortRangeBuilder(), dhcpSocket.getValue());
+                return srcMatch && dstMatch;
+            });
+            if (isDhcpRule) {
+                if (!inSameSubnet(localEp, peerEp)) {
+                    // do not process rules for DHCPs of other networks
+                    LOG.info("Rule: {} Not updating rules between {} and {}. Returning false.", rule,
+                            localEp.getAddress(), peerEp.getAddress());
+                    return false;
+                }
+                // do not update addresses for DHCP traffic
+                LOG.info("Rule: {} Not updating rule between {} and {}. Continue with next.", rule,
+                        localEp.getAddress(), peerEp.getAddress());
+                continue;
             }
-            return updateRules(rules, peerEp);
-        }
-        if (this instanceof DestinationMapper) {
-            if (AccessListUtil.ACE_DIRECTION.INGRESS.equals(direction)) {
-                return updateRules(rules, peerEp);
+            if (this instanceof SourceMapper) {
+                LOG.info("Rule: {} Updating rule between {} and {}. SourceMapper.", rule, localEp.getAddress(),
+                        peerEp.getAddress());
+                if (AccessListUtil.ACE_DIRECTION.INGRESS.equals(direction)) {
+                    updateRule(localEp, rule);
+                    continue;
+                }
+                updateRule(peerEp, rule);
+            } else if (this instanceof DestinationMapper) {
+                LOG.info("Rule: {} Updating rule between {} and {}. SourceMapper.", rule, localEp.getAddress(),
+                        peerEp.getAddress());
+                if (AccessListUtil.ACE_DIRECTION.INGRESS.equals(direction)) {
+                    updateRule(peerEp, rule);
+                    continue;
+                }
+                updateRule(localEp, rule);
             }
-            return updateRules(rules, localEp);
         }
-        return rules;
+        LOG.info("Updating rules between {} and {}. Done, returning true.",
+                localEp.getAddress(), peerEp.getAddress());
+        return true;
     }
 
-    private List<GbpAceBuilder> updateRules(List<GbpAceBuilder> rules, AddressEndpointWithLocation addrEp) {
-        for (GbpAceBuilder rule : rules) {
-            if (isInRange(rule.getSourcePortRangeBuilder(), DHCP_67)
-                    && isInRange(rule.getDestinationPortRangeBuilder(), DHCP_68)) {
-                continue;
-            }
-            if (isInRange(rule.getSourcePortRangeBuilder(), DHCP_68)
-                    && isInRange(rule.getDestinationPortRangeBuilder(), DHCP_67)) {
-                continue;
-            }
-            if (isInRange(rule.getSourcePortRangeBuilder(), DHCPV6_547)
-                    && isInRange(rule.getDestinationPortRangeBuilder(), DHCPV6_548)) {
-                continue;
+    private void filterRulesWithIrrelevantAddresses(List<GbpAceBuilder> rules, AddressEndpointWithLocation localEp,
+            AddressEndpointWithLocation peerEp) {
+        try {
+            if (!IpPrefixType.class.equals(localEp.getAddressType())
+                    || !IpPrefixType.class.equals(peerEp.getAddressType())) {
+                return;
             }
-            if (isInRange(rule.getSourcePortRangeBuilder(), DHCPV6_548)
-                    && isInRange(rule.getDestinationPortRangeBuilder(), DHCPV6_547)) {
-                continue;
+            boolean addressV4Check = AccessListUtil.isIpv4Address(localEp.getAddress())
+                    && AccessListUtil.isIpv4Address(peerEp.getAddress());
+            boolean addressV6Check = AccessListUtil.isIpv6Address(localEp.getAddress())
+                    && AccessListUtil.isIpv6Address(peerEp.getAddress());
+            Predicate<GbpAceBuilder> p;
+            if (addressV4Check) {
+                p = rule -> rule.getEtherType().get() instanceof AceIpv6;
+            } else if (addressV6Check) {
+                p = rule -> rule.getEtherType().get() instanceof AceIpv4;
+            } else {
+                return;
             }
-            updateRule(addrEp, rule);
+            List<GbpAceBuilder> rulesToRemove = rules.stream()
+                .filter(rule -> rule.getEtherType().isPresent())
+                .filter(p)
+                .collect(Collectors.toList());
+            rulesToRemove.forEach(rule -> { LOG.info("Filtering rules by ethertype {}", rule); rules.remove(rule);});
+        } catch (UnknownHostException e) {
+            LOG.error("Failed to parse addresses {}", e);
+        }
+    }
+
+    private static boolean inSameSubnet(AddressEndpointWithLocation localEp, AddressEndpointWithLocation peerEp) {
+        List<Predicate<AddressEndpointWithLocation>> list = new ArrayList<>();
+        list.add(x -> x != null);
+        list.add(x -> x.getContextType().equals(L3Context.class));
+        list.add(x -> x.getChildEndpoint() != null && !x.getChildEndpoint().isEmpty());
+        list.add(x -> x.getAbsoluteLocation() != null);
+        list.add(x -> x.getChildEndpoint().get(0).getContextType().equals(L2BridgeDomain.class));
+        list.add(x -> x.getChildEndpoint().get(0).getAddressType().equals(MacAddressType.class));
+        if (list.stream().filter(i -> !i.apply(peerEp)).findFirst().isPresent()) {
+            return false;
         }
-        return rules;
+        return localEp.getChildEndpoint().get(0).getContextId().equals(peerEp.getChildEndpoint().get(0).getContextId());
     }
 
-    private boolean isInRange(SourcePortRangeBuilder spr, PortNumber portNumber) {
+    private static boolean isInRange(SourcePortRangeBuilder spr, PortNumber portNumber) {
         return spr != null && isInRange(spr.getLowerPort(), spr.getUpperPort(), portNumber);
     }
 
-    private boolean isInRange(DestinationPortRangeBuilder dpr, PortNumber portNumber) {
+    private static boolean isInRange(DestinationPortRangeBuilder dpr, PortNumber portNumber) {
         return dpr != null && isInRange(dpr.getLowerPort(),dpr.getUpperPort(), portNumber);
     }
 
-    private boolean isInRange(PortNumber lower, PortNumber upper, PortNumber ref) {
+    private static boolean isInRange(PortNumber lower, PortNumber upper, PortNumber ref) {
         if (lower != null && upper != null) {
             return (lower.getValue() <= ref.getValue()) && (ref.getValue() <= upper.getValue());
         }
index f3312a656815e76d658a1b2ad34b689758bd75e6..b912e16ce27e8b99506a25eed1231040036e0e93 100644 (file)
@@ -46,6 +46,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev170615.acl.ip.protocol.header.fields.ip.protocol.udp.UdpNodes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev170615.acl.ip.protocol.header.fields.ip.protocol.udp.UdpNodesBuilder;
 
+import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 
 public class GbpAceBuilder {
@@ -93,6 +94,10 @@ public class GbpAceBuilder {
         return action;
     }
 
+    public Optional<AceIpVersion> getEtherType() {
+        return (aceIpVersion != null) ? Optional.of(aceIpVersion) : Optional.absent();
+    }
+
     public GbpAceBuilder setProtocol(short protocol) {
         this.protocol = protocol;
         return this;
@@ -112,6 +117,16 @@ public class GbpAceBuilder {
         return this;
     }
 
+    public GbpAceBuilder setIpv4EtherType() {
+        this.aceIpVersion = new AceIpv4Builder().build();
+        return this;
+    }
+
+    public GbpAceBuilder setIpv6EtherType() {
+        this.aceIpVersion = new AceIpv6Builder().build();
+        return this;
+    }
+
     public GbpAceBuilder setIpAddresses(@Nullable Ipv4Prefix srcIp, @Nullable Ipv4Prefix dstIp) {
         AceIpv4Builder aceIpv4Builder = (aceIpv4 != null) ? new AceIpv4Builder(aceIpv4) : new AceIpv4Builder();
         if (srcIp != null) {
index 4799587a7754f33db6951572899296aedf6b6d3a..ce10b2ed7d3ec311f44d8e5f51084ab88263e9b2 100755 (executable)
@@ -71,10 +71,24 @@ public class EtherTypeClassifier extends Classifier {
 
     @Override
     GbpAceBuilder update(GbpAceBuilder ruleBuilder, Map<String, ParameterValue> params) {
-        // ETHER_TYPE matching not supported yet
+        Long etherType = getEtherTypeValue(params);
+        if (!ruleBuilder.getEtherType().isPresent() && etherType != null) {
+            if (EtherTypeClassifierDefinition.IPv4_VALUE.equals(etherType)) {
+                ruleBuilder.setIpv4EtherType();
+            } else if (EtherTypeClassifierDefinition.IPv6_VALUE.equals(etherType)) {
+                ruleBuilder.setIpv6EtherType();
+            }
+        }
         return ruleBuilder;
     }
 
+    private static Long getEtherTypeValue(Map<String, ParameterValue> params) {
+        if (params == null || params.get(EtherTypeClassifierDefinition.ETHERTYPE_PARAM) == null) {
+            return null;
+        }
+        return params.get(EtherTypeClassifierDefinition.ETHERTYPE_PARAM).getIntValue();
+    }
+
     @Override
     void checkPrereqs(GbpAceBuilder matchBuilders) {
         // Nothing to consider yet.
index 6024bac5b4a3e7b9ec0f5761c71e07043a4f4859..62f4cb5fbe8f52aaa5662deb0296ad998ea8c26a 100644 (file)
@@ -39,6 +39,11 @@ public class KeyFactory {
                 fromKey.getContextType());
     }
 
+    public static AddressEndpointKey addressEndpointKey(PeerEndpointKey fromKey) {
+        return new AddressEndpointKey(fromKey.getAddress(), fromKey.getAddressType(), fromKey.getContextId(),
+                fromKey.getContextType());
+    }
+
     public static ProviderAddressEndpointLocationKey providerAddressEndpointLocationKey(
             AddressEndpointWithLocationKey fromKey) {
         return new ProviderAddressEndpointLocationKey(fromKey.getAddress(), fromKey.getAddressType(),
index 32a58ff30e251da4d8c6926dd654623aab1dd49a..4b618758018a7760c8c682c9176c8022a5a8916c 100644 (file)
@@ -30,6 +30,7 @@ import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
 import org.opendaylight.vbd.impl.transaction.VbdNetconfTransaction;
 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.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContextId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.endpoints.AddressEndpointWithLocation;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.endpoints.RendererEndpoint;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.endpoints.RendererEndpointKey;
@@ -64,7 +65,7 @@ public class AclManagerTest extends TestResources {
     @Test
     public void oneEndpointChanged() {
         List<Acl> acls = processChangedEndpoints(Sets.newHashSet(rendererEndpointKey(l3AddrEp1.getKey())), true);
-        Assert.assertEquals(acls.size(), 6);
+        Assert.assertEquals(6, acls.size());
         acls.forEach(acl -> {
             if (acl.getAclName().contains(VppPathMapper.interfacePathToInterfaceName(NODE1_CONNECTOR_1).get())) {
                 Assert.assertEquals(2 + 4, acl.getAccessListEntries().getAce().size());
@@ -73,10 +74,18 @@ public class AclManagerTest extends TestResources {
             }
         });
         acls = processChangedEndpoints(Sets.newHashSet(rendererEndpointKey(l3AddrEp1.getKey())), false);
-        Assert.assertEquals(acls.size(), 6);
+        Assert.assertEquals(6, acls.size());
         acls.forEach(acl -> {
+            System.out.println("DEBUGX " + acl);
             if (acl.getAclName().contains(VppPathMapper.interfacePathToInterfaceName(NODE1_CONNECTOR_1).get())) {
-                Assert.assertEquals(2, acl.getAccessListEntries().getAce().size());
+                acl.getAccessListEntries().getAce().forEach(ace -> {
+                    System.out.println("DEBUG1 " + ace);
+                });
+                /*
+                 * TODO rules were not removed, entire ACL is removed elsewhere when interface at
+                 * NODE1_CONNECTOR_1 detaches from bridge domain.
+                 */
+                Assert.assertEquals(6, acl.getAccessListEntries().getAce().size());
             } else {
                 Assert.assertEquals(2, acl.getAccessListEntries().getAce().size());
             }
@@ -89,8 +98,7 @@ public class AclManagerTest extends TestResources {
         Assert.assertEquals(acls.size(), 4);
         acls.forEach(acl -> {
             if (acl.getAclName().contains(VppPathMapper.interfacePathToInterfaceName(NODE1_CONNECTOR_1).get())) {
-                // TODO fix so that the following assert is uncomemnted
-                // Assert.assertEquals(2 + 2, acl.getAccessListEntries().getAce().size());
+                 Assert.assertEquals(2 + 4, acl.getAccessListEntries().getAce().size());
             } else {
                 Assert.assertEquals(2 + 2, acl.getAccessListEntries().getAce().size());
             }
@@ -99,11 +107,57 @@ public class AclManagerTest extends TestResources {
         Assert.assertEquals(acls.size(), 4);
         acls.forEach(acl -> {
             if (acl.getAclName().contains(VppPathMapper.interfacePathToInterfaceName(NODE1_CONNECTOR_1).get())) {
+                // Peer is updated 4 rules went to 2.
                 Assert.assertEquals(2, acl.getAccessListEntries().getAce().size());
             } else {
+             // Entire ACL is removed elsewhere -> no update of rules needed.
+                Assert.assertEquals(4, acl.getAccessListEntries().getAce().size());
+            }
+        });
+    }
+
+    /**
+     * Tests DHCP rules configuration. There should be no entries for DHCP servers serving different
+     * subnets, i.e.
+     * hosts should only have rules for accessing DHCP server in their subnet.
+     */
+    @Test
+    public void dhcpDifferentSubnets() {
+        final String ep4Mac = "20:00:00:00:00:02";
+        final String ep4Ip = "20.0.0.2/32";
+        final ContextId l2BdId2 = new ContextId("l2BridgeDomainId2");
+        final String node1Connector4 =
+                "/ietf-interfaces:interfaces/ietf-interfaces:interface[ietf-interfaces:name='nodeConnector4']";
+        final AddressEndpointWithLocation l2DhcpEp = l2AddressEndpointWithLocation(ep4Mac, l2BdId2, ep4Ip, L3_CTX_ID);
+        final AddressEndpointWithLocation l3DhcpEp = appendLocationToEndpoint(
+                l3AddressEndpointWithLocation(ep4Mac, l2BdId2, ep4Ip, L3_CTX_ID), NODE1, node1Connector4);
+        List<AddressEndpointWithLocation> addrEps = createAddressEndpoints();
+        addrEps.add(l2DhcpEp);
+        addrEps.add(l3DhcpEp);
+        List<RendererEndpoint> rEps = new ArrayList<>();
+        // DHCP from different subnet
+        rEps.add(createRendEndpoint(rendererEndpointKey(l3DhcpEp.getKey()), SECURITY_GROUP.SERVER,
+                peerEndpointKey(l3AddrEp2.getKey()), peerEndpointKey(l3AddrEp3.getKey())));
+        // DHCP from local subnet
+        rEps.add(createRendEndpoint(rendererEndpointKey(l3AddrEp1.getKey()), SECURITY_GROUP.SERVER,
+                peerEndpointKey(l3AddrEp2.getKey()), peerEndpointKey(l3AddrEp3.getKey())));
+        rEps.add(createRendEndpoint(rendererEndpointKey(l3AddrEp2.getKey()), SECURITY_GROUP.CLIENT,
+                peerEndpointKey(l3AddrEp1.getKey()), peerEndpointKey(l3DhcpEp.getKey())));
+        rEps.add(createRendEndpoint(rendererEndpointKey(l3AddrEp3.getKey()), SECURITY_GROUP.CLIENT,
+                peerEndpointKey(l3AddrEp1.getKey()), peerEndpointKey(l3DhcpEp.getKey())));
+        ctx = super.createPolicyContext(addrEps, rEps, createRuleGroupsDhcpTest(), createForwarding());
+        List<Acl> acls = processChangedEndpoints(Sets.newHashSet(rendererEndpointKey(l3AddrEp2.getKey())), true);
+        Assert.assertEquals(acls.size(), 6);
+        acls.forEach(acl -> {
+            if (acl.getAclName().contains(VppPathMapper.interfacePathToInterfaceName(node1Connector4).get())) {
                 Assert.assertEquals(2, acl.getAccessListEntries().getAce().size());
+            } else if (acl.getAclName().contains(VppPathMapper.interfacePathToInterfaceName(NODE1_CONNECTOR_1).get())) {
+                Assert.assertEquals(6, acl.getAccessListEntries().getAce().size());
+            } else {
+                Assert.assertEquals(4, acl.getAccessListEntries().getAce().size());
             }
         });
+
     }
 
     /**
@@ -128,7 +182,8 @@ public class AclManagerTest extends TestResources {
             if (acl.getAclName().contains(VppPathMapper.interfacePathToInterfaceName(NODE1_CONNECTOR_1).get())) {
                 Assert.assertEquals(2, acl.getAccessListEntries().getAce().size());
             } else {
-                Assert.assertEquals(2, acl.getAccessListEntries().getAce().size());
+                // Entire ACL is removed elsewhere -> no update of rules needed.
+                Assert.assertEquals(6, acl.getAccessListEntries().getAce().size());
             }
         });
     }
index 79910089b4dbebaca03c26c9a4d64fe750786529..7642243bfc6c76210522e42474d257643794263d 100644 (file)
@@ -278,7 +278,7 @@ public class TestResources extends CustomDataBrokerTest {
         return new RuleGroupsBuilder().setRuleGroup(ImmutableList.<RuleGroup>of(rg1, rg2)).build();
     }
 
-    public RuleGroups createRuleGroups_DhcpTest() {
+    public RuleGroups createRuleGroupsDhcpTest() {
         ParameterValue ipv4Param = new ParameterValueBuilder().setIntValue(EtherTypeClassifierDefinition.IPv4_VALUE)
             .setName(new ParameterName(EtherTypeClassifierDefinition.ETHERTYPE_PARAM))
             .build();
@@ -288,9 +288,15 @@ public class TestResources extends CustomDataBrokerTest {
         ParameterValue udpParam = new ParameterValueBuilder().setIntValue(IpProtoClassifierDefinition.UDP_VALUE)
             .setName(new ParameterName(IpProtoClassifierDefinition.PROTO_PARAM))
             .build();
+        ParameterValue srcDhcp = new ParameterValueBuilder().setIntValue(Long.valueOf(68))
+                .setName(new ParameterName(L4ClassifierDefinition.SRC_PORT_PARAM))
+                .build();
+        ParameterValue dstDhcp = new ParameterValueBuilder().setIntValue(Long.valueOf(67))
+                .setName(new ParameterName(L4ClassifierDefinition.DST_PORT_PARAM))
+                .build();
         RuleGroup rg1 = createSimpleRuleGroups(ImmutableList.of(ipv4Param, tcpParam), IpProtoClassifierDefinition.ID,
                 SUBJECT_NAME);
-        RuleGroup rg2 = createSimpleRuleGroups(ImmutableList.of(ipv4Param, udpParam), IpProtoClassifierDefinition.ID,
+        RuleGroup rg2 = createSimpleRuleGroups(ImmutableList.of(ipv4Param, udpParam, srcDhcp, dstDhcp), L4ClassifierDefinition.ID,
                 SUBJECT_NAME2);
         return new RuleGroupsBuilder().setRuleGroup(ImmutableList.<RuleGroup>of(rg1, rg2)).build();
     }
@@ -298,12 +304,12 @@ public class TestResources extends CustomDataBrokerTest {
     private RuleGroup createSimpleRuleGroups(List<ParameterValue> pv, ClassifierDefinitionId id,
             SubjectName subjectName) {
         final ClassifierName classifierName = new ClassifierName("cl-name");
-        Classifier classifIn = new ClassifierBuilder().setClassifierDefinitionId(IpProtoClassifierDefinition.ID)
+        Classifier classifIn = new ClassifierBuilder().setClassifierDefinitionId(id)
             .setDirection(Direction.In)
             .setName(classifierName)
             .setParameterValue(pv)
             .build();
-        Classifier classifOut = new ClassifierBuilder().setClassifierDefinitionId(IpProtoClassifierDefinition.ID)
+        Classifier classifOut = new ClassifierBuilder().setClassifierDefinitionId(id)
             .setDirection(Direction.Out)
             .setName(classifierName)
             .setParameterValue(pv)