2 * Copyright (c) 2016 Red Hat, Inc. and others. All rights reserved.
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
8 package org.opendaylight.netvirt.aclservice.tests;
10 import static com.google.common.truth.Truth.assertThat;
11 import static org.junit.Assert.assertTrue;
12 import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.CONFIGURATION;
13 import static org.opendaylight.mdsal.binding.testutils.AssertDataObjects.assertEqualBeans;
14 import static org.opendaylight.netvirt.aclservice.tests.StateInterfaceBuilderHelper.putNewStateInterface;
16 import com.google.common.collect.Iterables;
17 import com.google.common.collect.Lists;
18 import java.util.Arrays;
19 import java.util.List;
20 import java.util.stream.Collectors;
21 import javax.inject.Inject;
22 import org.junit.Before;
23 import org.junit.Test;
24 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
25 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
26 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
27 import org.opendaylight.genius.datastoreutils.testutils.AsyncEventsWaiter;
28 import org.opendaylight.genius.mdsalutil.FlowEntity;
29 import org.opendaylight.genius.mdsalutil.NwConstants;
30 import org.opendaylight.genius.mdsalutil.interfaces.testutils.TestIMdsalApiManager;
31 import org.opendaylight.netvirt.aclservice.tests.infra.DataBrokerPairsUtil;
32 import org.opendaylight.netvirt.aclservice.utils.AclConstants;
33 import org.opendaylight.netvirt.aclservice.utils.AclServiceUtils;
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.Matches;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.MatchesBuilder;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIpBuilder;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv4Builder;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
41 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160218.acl.transport.header.fields.DestinationPortRangeBuilder;
42 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
43 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.DirectionEgress;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.DirectionIngress;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.IpPrefixOrAddress;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.interfaces._interface.AllowedAddressPairs;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.interfaces._interface.AllowedAddressPairsBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterfaceBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.EthertypeBase;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.EthertypeV4;
55 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
56 import org.slf4j.Logger;
57 import org.slf4j.LoggerFactory;
60 public abstract class AclServiceTestBase {
62 private static final Logger LOG = LoggerFactory.getLogger(AclServiceTestBase.class);
64 static final String PORT_MAC_1 = "0D:AA:D8:42:30:F3";
65 static final String PORT_MAC_2 = "0D:AA:D8:42:30:F4";
66 static final String PORT_MAC_3 = "0D:AA:D8:42:30:F5";
67 static final String PORT_1 = "port1";
68 static final String PORT_2 = "port2";
69 static final String PORT_3 = "port3";
70 static String SG_UUID = "85cc3048-abc3-43cc-89b3-377341426ac5";
71 static String SR_UUID_1 = "85cc3048-abc3-43cc-89b3-377341426ac6";
72 static String SR_UUID_2 = "85cc3048-abc3-43cc-89b3-377341426ac7";
73 static String SG_UUID_1 = "85cc3048-abc3-43cc-89b3-377341426ac5";
74 static String SG_UUID_2 = "85cc3048-abc3-43cc-89b3-377341426ac8";
75 static String SR_UUID_1_1 = "85cc3048-abc3-43cc-89b3-377341426ac6";
76 static String SR_UUID_1_2 = "85cc3048-abc3-43cc-89b3-377341426ac7";
77 static String SR_UUID_2_1 = "85cc3048-abc3-43cc-89b3-377341426a21";
78 static String SR_UUID_2_2 = "85cc3048-abc3-43cc-89b3-377341426a22";
79 static String ELAN = "elan1";
80 static String IP_PREFIX_1 = "10.0.0.1/24";
81 static String IP_PREFIX_2 = "10.0.0.2/24";
82 static String IP_PREFIX_3 = "10.0.0.3/24";
83 static long ELAN_TAG = 5000L;
85 protected static final Integer FLOW_PRIORITY_SG_1 = 1001;
86 protected static final Integer FLOW_PRIORITY_SG_2 = 1002;
88 @Inject DataBroker dataBroker;
89 @Inject DataBrokerPairsUtil dataBrokerUtil;
90 SingleTransactionDataBroker singleTransactionDataBroker;
91 @Inject TestIMdsalApiManager mdsalApiManager;
92 @Inject AsyncEventsWaiter asyncEventsWaiter;
95 public void beforeEachTest() throws Exception {
96 singleTransactionDataBroker = new SingleTransactionDataBroker(dataBroker);
101 public void newInterface() throws Exception {
103 // putNewInterface(dataBroker, "port1", true, Collections.emptyList(), Collections.emptyList());
104 dataBrokerUtil.put(ImmutableIdentifiedInterfaceWithAclBuilder.builder()
105 .interfaceName("port1")
106 .portSecurity(true).build());
109 putNewStateInterface(dataBroker, "port1", PORT_MAC_1);
111 asyncEventsWaiter.awaitEventsConsumption();
117 abstract void newInterfaceCheck();
120 public void newInterfaceWithEtherTypeAcl() throws Exception {
121 Matches matches = newMatch(EthertypeV4.class, -1, -1,-1, -1,
122 null, AclConstants.IPV4_ALL_NETWORK, (short)-1);
123 dataBrokerUtil.put(ImmutableIdentifiedAceBuilder.builder()
125 .newRuleName(SR_UUID_1_1)
127 .newDirection(DirectionEgress.class)
130 matches = newMatch(EthertypeV4.class, -1, -1,-1, -1,
131 AclConstants.IPV4_ALL_NETWORK, null, (short)-1);
132 dataBrokerUtil.put(ImmutableIdentifiedAceBuilder.builder()
134 .newRuleName(SR_UUID_1_2)
136 .newDirection(DirectionIngress.class)
137 .newRemoteGroupId(new Uuid(SG_UUID_1)).build());
140 putNewStateInterface(dataBroker, PORT_1, PORT_MAC_1);
141 putNewStateInterface(dataBroker, PORT_2, PORT_MAC_2);
143 asyncEventsWaiter.awaitEventsConsumption();
146 newInterfaceWithEtherTypeAclCheck();
149 abstract void newInterfaceWithEtherTypeAclCheck();
152 public void newInterfaceWithTcpDstAcl() throws Exception {
154 Matches matches = newMatch(EthertypeV4.class, -1, -1, 80, 80,
155 null, AclConstants.IPV4_ALL_NETWORK, (short)NwConstants.IP_PROT_TCP);
156 dataBrokerUtil.put(ImmutableIdentifiedAceBuilder.builder()
158 .newRuleName(SR_UUID_1_1)
160 .newDirection(DirectionEgress.class)
161 .newRemoteGroupId(new Uuid(SG_UUID_1)).build());
162 matches = newMatch(EthertypeV4.class, -1, -1, 80, 80,
163 AclConstants.IPV4_ALL_NETWORK, null, (short)NwConstants.IP_PROT_TCP);
165 dataBrokerUtil.put(ImmutableIdentifiedAceBuilder.builder()
167 .newRuleName(SR_UUID_1_2)
169 .newDirection(DirectionIngress.class)
173 putNewStateInterface(dataBroker, PORT_1, PORT_MAC_1);
174 putNewStateInterface(dataBroker, PORT_2, PORT_MAC_2);
176 asyncEventsWaiter.awaitEventsConsumption();
179 newInterfaceWithTcpDstAclCheck();
182 abstract void newInterfaceWithTcpDstAclCheck();
185 public void newInterfaceWithUdpDstAcl() throws Exception {
187 Matches matches = newMatch(EthertypeV4.class, -1, -1, 80, 80,
188 null, AclConstants.IPV4_ALL_NETWORK, (short)NwConstants.IP_PROT_UDP);
189 dataBrokerUtil.put(ImmutableIdentifiedAceBuilder.builder()
191 .newRuleName(SR_UUID_1_1)
193 .newDirection(DirectionEgress.class)
196 matches = newMatch(EthertypeV4.class, -1, -1, 80, 80,
197 AclConstants.IPV4_ALL_NETWORK, null, (short)NwConstants.IP_PROT_UDP);
198 dataBrokerUtil.put(ImmutableIdentifiedAceBuilder.builder()
200 .newRuleName(SR_UUID_1_2)
202 .newDirection(DirectionIngress.class)
203 .newRemoteGroupId(new Uuid(SG_UUID_1)).build());
206 putNewStateInterface(dataBroker, PORT_1, PORT_MAC_1);
207 putNewStateInterface(dataBroker, PORT_2, PORT_MAC_2);
209 asyncEventsWaiter.awaitEventsConsumption();
212 newInterfaceWithUdpDstAclCheck();
215 abstract void newInterfaceWithUdpDstAclCheck();
218 public void newInterfaceWithIcmpAcl() throws Exception {
220 Matches matches = newMatch(EthertypeV4.class, -1, -1, 2, 3,
221 null, AclConstants.IPV4_ALL_NETWORK, (short)NwConstants.IP_PROT_ICMP);
222 dataBrokerUtil.put(ImmutableIdentifiedAceBuilder.builder()
224 .newRuleName(SR_UUID_1_1)
226 .newDirection(DirectionEgress.class)
227 .newRemoteGroupId(new Uuid(SG_UUID_1)).build());
229 matches = newMatch( EthertypeV4.class, -1, -1, 2, 3,
230 AclConstants.IPV4_ALL_NETWORK, null, (short)NwConstants.IP_PROT_ICMP);
231 dataBrokerUtil.put(ImmutableIdentifiedAceBuilder.builder()
233 .newRuleName(SR_UUID_1_2)
235 .newDirection(DirectionIngress.class)
239 putNewStateInterface(dataBroker, PORT_1, PORT_MAC_1);
240 putNewStateInterface(dataBroker, PORT_2, PORT_MAC_2);
242 asyncEventsWaiter.awaitEventsConsumption();
245 newInterfaceWithIcmpAclCheck();
248 abstract void newInterfaceWithIcmpAclCheck();
251 public void newInterfaceWithDstPortRange() throws Exception {
253 Matches matches = newMatch(EthertypeV4.class, -1, -1, 333, 777,
254 null, AclConstants.IPV4_ALL_NETWORK, (short)NwConstants.IP_PROT_TCP);
255 dataBrokerUtil.put(ImmutableIdentifiedAceBuilder.builder()
257 .newRuleName(SR_UUID_1_1)
259 .newDirection(DirectionEgress.class)
261 matches = newMatch(EthertypeV4.class, -1, -1, 2000, 2003,
262 AclConstants.IPV4_ALL_NETWORK, null, (short)NwConstants.IP_PROT_UDP);
264 dataBrokerUtil.put(ImmutableIdentifiedAceBuilder.builder()
266 .newRuleName(SR_UUID_1_2)
268 .newDirection(DirectionIngress.class)
272 putNewStateInterface(dataBroker, PORT_1, PORT_MAC_1);
274 asyncEventsWaiter.awaitEventsConsumption();
277 newInterfaceWithDstPortRangeCheck();
280 abstract void newInterfaceWithDstPortRangeCheck();
283 public void newInterfaceWithDstAllPorts() throws Exception {
285 Matches matches = newMatch(EthertypeV4.class, -1, -1, 1, 65535,
286 null, AclConstants.IPV4_ALL_NETWORK, (short)NwConstants.IP_PROT_TCP);
287 dataBrokerUtil.put(ImmutableIdentifiedAceBuilder.builder()
289 .newRuleName(SR_UUID_1_1)
291 .newDirection(DirectionEgress.class)
293 matches = newMatch(EthertypeV4.class, -1, -1, 1, 65535,
294 AclConstants.IPV4_ALL_NETWORK, null, (short)NwConstants.IP_PROT_UDP);
296 dataBrokerUtil.put(ImmutableIdentifiedAceBuilder.builder()
298 .newRuleName(SR_UUID_1_2)
300 .newDirection(DirectionIngress.class)
304 putNewStateInterface(dataBroker, PORT_1, PORT_MAC_1);
306 asyncEventsWaiter.awaitEventsConsumption();
309 newInterfaceWithDstAllPortsCheck();
312 abstract void newInterfaceWithDstAllPortsCheck();
315 public void newInterfaceWithTwoAclsHavingSameRules() throws Exception {
317 Matches icmpEgressMatches = newMatch(EthertypeV4.class, -1, -1, 2, 3, null, AclConstants.IPV4_ALL_NETWORK,
318 (short) NwConstants.IP_PROT_ICMP);
319 Matches icmpIngressMatches = newMatch(EthertypeV4.class, -1, -1, 2, 3, AclConstants.IPV4_ALL_NETWORK, null,
320 (short) NwConstants.IP_PROT_ICMP);
322 dataBrokerUtil.put(ImmutableIdentifiedAceBuilder.builder().sgUuid(SG_UUID_1).newRuleName(SR_UUID_1_1)
323 .newMatches(icmpEgressMatches).newDirection(DirectionEgress.class).build());
325 dataBrokerUtil.put(ImmutableIdentifiedAceBuilder.builder().sgUuid(SG_UUID_1).newRuleName(SR_UUID_1_2)
326 .newMatches(icmpIngressMatches).newDirection(DirectionIngress.class).build());
328 dataBrokerUtil.put(ImmutableIdentifiedAceBuilder.builder().sgUuid(SG_UUID_2).newRuleName(SR_UUID_2_1)
329 .newMatches(icmpEgressMatches).newDirection(DirectionEgress.class).build());
331 dataBrokerUtil.put(ImmutableIdentifiedAceBuilder.builder().sgUuid(SG_UUID_2).newRuleName(SR_UUID_2_2)
332 .newMatches(icmpIngressMatches).newDirection(DirectionIngress.class).build());
335 putNewStateInterface(dataBroker, PORT_3, PORT_MAC_3);
337 asyncEventsWaiter.awaitEventsConsumption();
340 newInterfaceWithTwoAclsHavingSameRulesCheck();
343 abstract void newInterfaceWithTwoAclsHavingSameRulesCheck();
345 // TODO Remove this from here, use the one about to be merged in TestIMdsalApiManager
346 // under https://git.opendaylight.org/gerrit/#/c/47842/ *BUT* remember to integrate
347 // the ignore ordering fix recently added here to there...
348 protected void assertFlowsInAnyOrder(Iterable<FlowEntity> expectedFlows) {
349 List<FlowEntity> flows = mdsalApiManager.getFlows();
350 if (!Iterables.isEmpty(expectedFlows)) {
351 assertTrue("No Flows created (bean wiring may be broken?)", !flows.isEmpty());
354 // TODO Support Iterable <-> List directly within XtendBeanGenerator
355 List<FlowEntity> expectedFlowsAsNewArrayList = Lists.newArrayList(expectedFlows);
357 // FYI: This containsExactlyElementsIn() assumes that FlowEntity, and everything in it,
358 // has correctly working equals() implementations. assertEqualBeans() does not assume
359 // that, and would work even without equals, because it only uses property reflection.
360 // Normally this will lead to the same result, but if one day it doesn't (because of
361 // a bug in an equals() implementation somewhere), then it's worth to keep this diff
364 // FTR: This use of G Truth and then catch AssertionError and using assertEqualBeans iff NOK
365 // (thus discarding the message from G Truth) is a bit of a hack, but it works well...
366 // If you're tempted to improve this, please remember that correctly re-implementing
367 // containsExactlyElementsIn (or Hamcrest's similar containsInAnyOrder) isn't a 1 line
368 // trivia... e.g. a.containsAll(b) && b.containsAll(a) isn't sufficient, because it
369 // won't work for duplicates (which we frequently have here); and ordering before is
370 // not viable because FlowEntity is not Comparable, and Comparator based on hashCode
371 // is not a good idea (different instances can have same hashCode), and e.g. on
372 // System#identityHashCode even less so.
374 LOG.info("expectedFlows = {}", expectedFlowsAsNewArrayList);
375 LOG.info("flows = {}",flows);
376 assertThat(flows).containsExactlyElementsIn(expectedFlowsAsNewArrayList);
377 } catch (AssertionError e) {
378 // The point of this is basically just that our assertEqualBeans output,
379 // in case of a comparison failure, is *A LOT* more clearly readable
380 // than what G Truth (or Hamcrest) can do based on toString.
381 assertEqualBeans(expectedFlowsAsNewArrayList, flows);
385 private void newAllowedAddressPair(String portName, List<String> sgUuidList, String ipAddress, String macAddress )
386 throws TransactionCommitFailedException {
387 AllowedAddressPairs allowedAddressPair = new AllowedAddressPairsBuilder()
388 .setIpAddress(new IpPrefixOrAddress(new IpPrefix(ipAddress.toCharArray())))
389 .setMacAddress(new MacAddress(macAddress))
391 List<Uuid> sgList = sgUuidList.stream().map(Uuid::new).collect(Collectors.toList());
393 dataBrokerUtil.put(ImmutableIdentifiedInterfaceWithAclBuilder.builder()
394 .interfaceName(portName)
396 .addAllNewSecurityGroups(sgList)
397 .addIfAllowedAddressPair(allowedAddressPair).build());
400 private void newElan(String elanName, long elanId) throws TransactionCommitFailedException {
401 ElanInstance elan = new ElanInstanceBuilder().setElanInstanceName(elanName).setElanTag(5000L).build();
402 singleTransactionDataBroker.syncWrite(CONFIGURATION,
403 AclServiceUtils.getElanInstanceConfigurationDataPath(elanName),
407 private void newElanInterface(String elanName, String portName, boolean isWrite)
408 throws TransactionCommitFailedException {
409 ElanInterface elanInterface = new ElanInterfaceBuilder().setName(portName)
410 .setElanInstanceName(elanName).build();
411 InstanceIdentifier<ElanInterface> id = AclServiceUtils.getElanInterfaceConfigurationDataPathId(portName);
413 singleTransactionDataBroker.syncWrite(CONFIGURATION, id, elanInterface);
415 singleTransactionDataBroker.syncDelete(CONFIGURATION, id);
419 // TODO refactor this instead of stealing it from org.opendaylight.netvirt.neutronvpn.NeutronSecurityRuleListener
420 private Matches newMatch( Class<? extends EthertypeBase> newEtherType,
421 int srcLowerPort, int srcUpperPort, int destLowerPort, int destupperPort, String srcRemoteIpPrefix,
422 String dstRemoteIpPrefix, short protocol) {
423 AceIpBuilder aceIpBuilder = new AceIpBuilder();
424 if (destLowerPort != -1) {
425 DestinationPortRangeBuilder destinationPortRangeBuilder = new DestinationPortRangeBuilder();
426 destinationPortRangeBuilder.setLowerPort(new PortNumber(destLowerPort));
427 destinationPortRangeBuilder.setUpperPort(new PortNumber(destupperPort));
428 aceIpBuilder.setDestinationPortRange(destinationPortRangeBuilder.build());
430 AceIpv4Builder aceIpv4Builder = new AceIpv4Builder();
431 if (srcRemoteIpPrefix != null) {
432 aceIpv4Builder.setSourceIpv4Network(new Ipv4Prefix(srcRemoteIpPrefix));
434 if (dstRemoteIpPrefix != null) {
435 aceIpv4Builder.setSourceIpv4Network(new Ipv4Prefix(dstRemoteIpPrefix));
437 if (protocol != -1) {
438 aceIpBuilder.setProtocol(protocol);
440 aceIpBuilder.setAceIpVersion(aceIpv4Builder.build());
442 MatchesBuilder matchesBuilder = new MatchesBuilder();
443 matchesBuilder.setAceType(aceIpBuilder.build());
444 return matchesBuilder.build();
448 public void setUpData() throws Exception {
449 newElan(ELAN, ELAN_TAG);
450 newElanInterface(ELAN, PORT_1 ,true);
451 newElanInterface(ELAN, PORT_2, true);
452 newElanInterface(ELAN, PORT_3, true);
453 newAllowedAddressPair(PORT_1, Arrays.asList(SG_UUID_1), IP_PREFIX_1, PORT_MAC_1);
454 newAllowedAddressPair(PORT_2, Arrays.asList(SG_UUID_1), IP_PREFIX_2, PORT_MAC_2);
455 newAllowedAddressPair(PORT_3, Arrays.asList(SG_UUID_1, SG_UUID_2), IP_PREFIX_3, PORT_MAC_3);