Upgrading ACL implementation
[groupbasedpolicy.git] / renderers / vpp / src / test / java / org / opendaylight / groupbasedpolicy / renderer / vpp / policy / acl / AclManagerTest.java
1 /*
2  * Copyright (c) 2017 Cisco Systems, Inc. and others. All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.groupbasedpolicy.renderer.vpp.policy.acl;
10
11 import java.util.AbstractMap;
12 import java.util.ArrayList;
13 import java.util.List;
14 import java.util.Set;
15 import java.util.concurrent.locks.ReentrantLock;
16
17 import org.junit.Assert;
18 import org.junit.Before;
19 import org.junit.Test;
20 import org.mockito.Mockito;
21 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
22 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
23 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
24 import org.opendaylight.groupbasedpolicy.renderer.vpp.iface.InterfaceManager;
25 import org.opendaylight.groupbasedpolicy.renderer.vpp.iface.VppPathMapper;
26 import org.opendaylight.groupbasedpolicy.renderer.vpp.policy.PolicyContext;
27 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.MountedDataBrokerProvider;
28 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.VppIidFactory;
29 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
30 import org.opendaylight.vbd.impl.transaction.VbdNetconfTransaction;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.AccessLists;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContextId;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.endpoints.AddressEndpointWithLocation;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.endpoints.RendererEndpoint;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.endpoints.RendererEndpointKey;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.rule.groups.RuleGroupKey;
38 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
39 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
40
41 import com.google.common.base.Optional;
42 import com.google.common.collect.Sets;
43 import com.google.common.collect.Sets.SetView;
44
45 public class AclManagerTest extends TestResources {
46
47     private PolicyContext ctx;
48     private MountedDataBrokerProvider mountedDataProviderMock;
49     private DataBroker mountPointDataBroker;
50     private AclManager aclManager;
51
52     @Before
53     public void init() {
54         ctx = super.createPolicyContext(createAddressEndpoints(), createRendEps(), createRuleGroups(),
55                 createForwarding());
56         mountedDataProviderMock = Mockito.mock(MountedDataBrokerProvider.class);
57         mountPointDataBroker = getDataBroker();
58         aclManager = new AclManager(mountedDataProviderMock, Mockito.mock(InterfaceManager.class));
59         Mockito.when(mountedDataProviderMock.resolveDataBrokerForMountPoint(Mockito.any(InstanceIdentifier.class)))
60             .thenReturn(Optional.of(mountPointDataBroker));
61         VbdNetconfTransaction.NODE_DATA_BROKER_MAP.put(VppIidFactory.getNetconfNodeIid(new NodeId("node1")),
62                 new AbstractMap.SimpleEntry<DataBroker, ReentrantLock>(mountPointDataBroker, new ReentrantLock()));
63     }
64
65     @Test
66     public void oneEndpointChanged() {
67         List<Acl> acls = processChangedEndpoints(Sets.newHashSet(rendererEndpointKey(l3AddrEp1.getKey())), true);
68         Assert.assertEquals(6, acls.size());
69         acls.forEach(acl -> {
70             if (acl.getAclName().contains(VppPathMapper.interfacePathToInterfaceName(NODE1_CONNECTOR_1).get())) {
71                 Assert.assertEquals(2 + 4, acl.getAccessListEntries().getAce().size());
72             } else {
73                 Assert.assertEquals(2 + 2, acl.getAccessListEntries().getAce().size());
74             }
75         });
76         acls = processChangedEndpoints(Sets.newHashSet(rendererEndpointKey(l3AddrEp1.getKey())), false);
77         Assert.assertEquals(6, acls.size());
78         acls.forEach(acl -> {
79             System.out.println("DEBUGX " + acl);
80             if (acl.getAclName().contains(VppPathMapper.interfacePathToInterfaceName(NODE1_CONNECTOR_1).get())) {
81                 acl.getAccessListEntries().getAce().forEach(ace -> {
82                     System.out.println("DEBUG1 " + ace);
83                 });
84                 /*
85                  * TODO rules were not removed, entire ACL is removed elsewhere when interface at
86                  * NODE1_CONNECTOR_1 detaches from bridge domain.
87                  */
88                 Assert.assertEquals(6, acl.getAccessListEntries().getAce().size());
89             } else {
90                 Assert.assertEquals(2, acl.getAccessListEntries().getAce().size());
91             }
92         });
93     }
94
95     @Test
96     public void oneEndpointChanged_createRulesOnlyForChangedEpInPeer() {
97         List<Acl> acls = processChangedEndpoints(Sets.newHashSet(rendererEndpointKey(l3AddrEp2.getKey())), true);
98         Assert.assertEquals(acls.size(), 4);
99         acls.forEach(acl -> {
100             if (acl.getAclName().contains(VppPathMapper.interfacePathToInterfaceName(NODE1_CONNECTOR_1).get())) {
101                  Assert.assertEquals(2 + 4, acl.getAccessListEntries().getAce().size());
102             } else {
103                 Assert.assertEquals(2 + 2, acl.getAccessListEntries().getAce().size());
104             }
105         });
106         acls = processChangedEndpoints(Sets.newHashSet(rendererEndpointKey(l3AddrEp2.getKey())), false);
107         Assert.assertEquals(acls.size(), 4);
108         acls.forEach(acl -> {
109             if (acl.getAclName().contains(VppPathMapper.interfacePathToInterfaceName(NODE1_CONNECTOR_1).get())) {
110                 // Peer is updated 4 rules went to 2.
111                 Assert.assertEquals(2, acl.getAccessListEntries().getAce().size());
112             } else {
113              // Entire ACL is removed elsewhere -> no update of rules needed.
114                 Assert.assertEquals(4, acl.getAccessListEntries().getAce().size());
115             }
116         });
117     }
118
119     /**
120      * Tests DHCP rules configuration. There should be no entries for DHCP servers serving different
121      * subnets, i.e.
122      * hosts should only have rules for accessing DHCP server in their subnet.
123      */
124     @Test
125     public void dhcpDifferentSubnets() {
126         final String ep4Mac = "20:00:00:00:00:02";
127         final String ep4Ip = "20.0.0.2/32";
128         final ContextId l2BdId2 = new ContextId("l2BridgeDomainId2");
129         final String node1Connector4 =
130                 "/ietf-interfaces:interfaces/ietf-interfaces:interface[ietf-interfaces:name='nodeConnector4']";
131         final AddressEndpointWithLocation l2DhcpEp = l2AddressEndpointWithLocation(ep4Mac, l2BdId2, ep4Ip, L3_CTX_ID);
132         final AddressEndpointWithLocation l3DhcpEp = appendLocationToEndpoint(
133                 l3AddressEndpointWithLocation(ep4Mac, l2BdId2, ep4Ip, L3_CTX_ID), NODE1, node1Connector4);
134         List<AddressEndpointWithLocation> addrEps = createAddressEndpoints();
135         addrEps.add(l2DhcpEp);
136         addrEps.add(l3DhcpEp);
137         List<RendererEndpoint> rEps = new ArrayList<>();
138         // DHCP from different subnet
139         rEps.add(createRendEndpoint(rendererEndpointKey(l3DhcpEp.getKey()), SECURITY_GROUP.SERVER,
140                 peerEndpointKey(l3AddrEp2.getKey()), peerEndpointKey(l3AddrEp3.getKey())));
141         // DHCP from local subnet
142         rEps.add(createRendEndpoint(rendererEndpointKey(l3AddrEp1.getKey()), SECURITY_GROUP.SERVER,
143                 peerEndpointKey(l3AddrEp2.getKey()), peerEndpointKey(l3AddrEp3.getKey())));
144         rEps.add(createRendEndpoint(rendererEndpointKey(l3AddrEp2.getKey()), SECURITY_GROUP.CLIENT,
145                 peerEndpointKey(l3AddrEp1.getKey()), peerEndpointKey(l3DhcpEp.getKey())));
146         rEps.add(createRendEndpoint(rendererEndpointKey(l3AddrEp3.getKey()), SECURITY_GROUP.CLIENT,
147                 peerEndpointKey(l3AddrEp1.getKey()), peerEndpointKey(l3DhcpEp.getKey())));
148         ctx = super.createPolicyContext(addrEps, rEps, createRuleGroupsDhcpTest(), createForwarding());
149         List<Acl> acls = processChangedEndpoints(Sets.newHashSet(rendererEndpointKey(l3AddrEp2.getKey())), true);
150         Assert.assertEquals(acls.size(), 6);
151         acls.forEach(acl -> {
152             if (acl.getAclName().contains(VppPathMapper.interfacePathToInterfaceName(node1Connector4).get())) {
153                 Assert.assertEquals(2, acl.getAccessListEntries().getAce().size());
154             } else if (acl.getAclName().contains(VppPathMapper.interfacePathToInterfaceName(NODE1_CONNECTOR_1).get())) {
155                 Assert.assertEquals(6, acl.getAccessListEntries().getAce().size());
156             } else {
157                 Assert.assertEquals(4, acl.getAccessListEntries().getAce().size());
158             }
159         });
160
161     }
162
163     /**
164      * Metadata use case. DHCP endpoint and metadata endpoint are on the same access interface and
165      * so their entries meet in one ACL.
166      */
167     @Test
168     public void oneEndpointChanged_metadataUseCase() {
169         createContextFormetadataUseCase();
170         List<Acl> acls = processChangedEndpoints(Sets.newHashSet(rendererEndpointKey(l3AddrEp2.getKey())), true);
171         Assert.assertEquals(acls.size(), 4);
172         acls.forEach(acl -> {
173             if (acl.getAclName().contains(VppPathMapper.interfacePathToInterfaceName(NODE1_CONNECTOR_1).get())) {
174                 Assert.assertEquals(10, acl.getAccessListEntries().getAce().size());
175             } else {
176                 Assert.assertEquals(6, acl.getAccessListEntries().getAce().size());
177             }
178         });
179         acls = processChangedEndpoints(Sets.newHashSet(rendererEndpointKey(l3AddrEp2.getKey())), false);
180         Assert.assertEquals(acls.size(), 4);
181         acls.forEach(acl -> {
182             if (acl.getAclName().contains(VppPathMapper.interfacePathToInterfaceName(NODE1_CONNECTOR_1).get())) {
183                 Assert.assertEquals(2, acl.getAccessListEntries().getAce().size());
184             } else {
185                 // Entire ACL is removed elsewhere -> no update of rules needed.
186                 Assert.assertEquals(6, acl.getAccessListEntries().getAce().size());
187             }
188         });
189     }
190
191     public void createContextFormetadataUseCase() {
192         String ep4Mac = "11:11:22:22:44:44";
193         String ep4Ip = "10.0.0.40/32";
194         final AddressEndpointWithLocation l2MetadataEp =
195                 l2AddressEndpointWithLocation(ep4Mac, L2_BD_ID, ep4Ip, L3_CTX_ID);
196         final AddressEndpointWithLocation l3MetadataEp = appendLocationToEndpoint(
197                 l3AddressEndpointWithLocation(ep4Mac, L2_BD_ID, ep4Ip, L3_CTX_ID), NODE1, NODE1_CONNECTOR_1);
198         List<AddressEndpointWithLocation> addrEps = createAddressEndpoints();
199         addrEps.add(l2MetadataEp);
200         addrEps.add(l3MetadataEp);
201         List<RendererEndpoint> rEps = new ArrayList<>();
202         rEps.add(createRendEndpoint(rendererEndpointKey(l3AddrEp1.getKey()), SECURITY_GROUP.SERVER,
203                 peerEndpointKey(l3AddrEp2.getKey()), peerEndpointKey(l3AddrEp3.getKey())));
204         rEps.add(createRendEndpoint(rendererEndpointKey(l3MetadataEp.getKey()), SECURITY_GROUP.SERVER,
205                 peerEndpointKey(l3AddrEp2.getKey()), peerEndpointKey(l3AddrEp3.getKey())));
206         rEps.add(createRendEndpoint(rendererEndpointKey(l3AddrEp2.getKey()), SECURITY_GROUP.CLIENT,
207                 peerEndpointKey(l3AddrEp1.getKey()), peerEndpointKey(l3MetadataEp.getKey())));
208         rEps.add(createRendEndpoint(rendererEndpointKey(l3AddrEp3.getKey()), SECURITY_GROUP.CLIENT,
209                 peerEndpointKey(l3AddrEp1.getKey()), peerEndpointKey(l3MetadataEp.getKey())));
210         ctx = super.createPolicyContext(addrEps, rEps, createRuleGroups(), createForwarding());
211     }
212
213     public List<Acl> processChangedEndpoints(Set<RendererEndpointKey> changedEndpoints, boolean created) {
214         aclManager.cacheEndpointsByInterfaces(ctx);
215         SetView<RendererEndpointKey> deltaEndpoints = Sets.difference(changedEndpoints, Sets.newHashSet());
216         SetView<RuleGroupKey> deltaRules = Sets.intersection(Sets.newHashSet(), Sets.newHashSet());
217         aclManager.resolveRulesToConfigure(ctx, deltaEndpoints, deltaRules, created);
218         ReadOnlyTransaction rTx = mountPointDataBroker.newReadOnlyTransaction();
219         Optional<AccessLists> readAccessLists = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
220                 InstanceIdentifier.builder(AccessLists.class).build(), rTx);
221         rTx.close();
222         Assert.assertTrue(readAccessLists.isPresent());
223         return readAccessLists.get().getAcl();
224     }
225
226     @Test
227     public void oneRuleChanged() {
228         processAndAssertChangedRules(Sets.newHashSet(new RuleGroupKey(CONTRACT_ID, SUBJECT_NAME, TENANT_ID)), true);
229         processAndAssertChangedRules(Sets.newHashSet(new RuleGroupKey(CONTRACT_ID, SUBJECT_NAME, TENANT_ID)), false);
230     }
231
232     @Test
233     public void twoRulesChanged() {
234         processAndAssertChangedRules(Sets.newHashSet(new RuleGroupKey(CONTRACT_ID, SUBJECT_NAME, TENANT_ID),
235                 new RuleGroupKey(CONTRACT_ID, SUBJECT_NAME2, TENANT_ID)), true);
236         processAndAssertChangedRules(Sets.newHashSet(new RuleGroupKey(CONTRACT_ID, SUBJECT_NAME, TENANT_ID),
237                 new RuleGroupKey(CONTRACT_ID, SUBJECT_NAME2, TENANT_ID)), false);
238     }
239
240     public void processAndAssertChangedRules(Set<RuleGroupKey> createdRuleGroups, boolean created) {
241         aclManager.cacheEndpointsByInterfaces(ctx);
242         SetView<RendererEndpointKey> deltaRendEp = Sets.intersection(Sets.newHashSet(), Sets.newHashSet());
243         SetView<RuleGroupKey> deltaRuleGroups = Sets.difference(createdRuleGroups, Sets.newHashSet());
244         aclManager.resolveRulesToConfigure(ctx, deltaRendEp, deltaRuleGroups, created);
245         ReadOnlyTransaction rTx = mountPointDataBroker.newReadOnlyTransaction();
246         Optional<AccessLists> readAccessLists = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
247                 InstanceIdentifier.builder(AccessLists.class).build(), rTx);
248         rTx.close();
249         Assert.assertTrue(readAccessLists.isPresent());
250         List<Acl> acls = readAccessLists.get().getAcl();
251         Assert.assertEquals(acls.size(), 6);
252         acls.forEach(acl -> {
253             int diff;
254             if (acl.getAclName().contains(VppPathMapper.interfacePathToInterfaceName(NODE1_CONNECTOR_1).get())) {
255                 diff = 2 * createdRuleGroups.size() * ((created) ? 1 : 0);
256             } else {
257                 diff = createdRuleGroups.size() * ((created) ? 1 : 0);
258             }
259             Assert.assertEquals(2 + diff, acl.getAccessListEntries().getAce().size());
260         });
261     }
262 }