2 * Copyright © 2017 Ericsson India Global Services Pvt Ltd. 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.elanmanager.tests;
10 import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.CONFIGURATION;
12 import com.google.common.collect.Sets;
13 import java.util.ArrayList;
14 import java.util.Collections;
15 import java.util.List;
18 import java.util.concurrent.ExecutionException;
19 import java.util.function.BiPredicate;
20 import java.util.function.Function;
21 import java.util.stream.Collectors;
22 import org.awaitility.core.ConditionFactory;
23 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
24 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
25 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
26 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
27 import org.opendaylight.genius.mdsalutil.MDSALUtil;
28 import org.opendaylight.genius.mdsalutil.NwConstants;
29 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
30 import org.opendaylight.genius.testutils.interfacemanager.TunnelInterfaceDetails;
31 import org.opendaylight.mdsal.binding.testutils.AssertDataObjects;
32 import org.opendaylight.netvirt.elan.utils.ElanUtils;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceInput;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceInputBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.BucketId;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.BucketBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.BucketKey;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceKey;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteUcastMacs;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSet;
60 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId;
61 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
62 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
63 import org.opendaylight.yangtools.yang.binding.DataObject;
64 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
65 import org.opendaylight.yangtools.yang.common.Uint32;
66 import org.opendaylight.yangtools.yang.common.Uint64;
68 public class Verifications {
70 private static final boolean CHECK_FOR_EXISTS = true;
71 private static final boolean CHECK_FOR_DELETED = false;
72 private static final Function<Uint64, NodeId> GET_OPENFLOW_NODE_ID = (dpnId) -> new NodeId("openflow:" + dpnId);
73 private static final InstanceIdentifier<ElanInstance> ELAN_IID = InstanceIdentifier
74 .builder(ElanInstances.class)
75 .child(ElanInstance.class, new ElanInstanceKey(ExpectedObjects.ELAN1))
77 private static final BiPredicate<Group, Group> BUCKETS_SIZE_MIS_MATCHED = (actual, expected) -> {
78 return !(actual.getBuckets().getBucket().size() == expected.getBuckets().getBucket().size());
81 private final SingleTransactionDataBroker singleTxdataBroker;
82 private final OdlInterfaceRpcService odlInterfaceRpcService;
83 private final Map<String, TunnelInterfaceDetails> extnIntfs;
84 private final ConditionFactory awaiter;
86 public Verifications(final SingleTransactionDataBroker singleTxdataBroker,
87 final OdlInterfaceRpcService odlInterfaceRpcService,
88 final Map<String, TunnelInterfaceDetails> extnIntfs,
89 final ConditionFactory awaiter) {
90 this.singleTxdataBroker = singleTxdataBroker;
91 this.odlInterfaceRpcService = odlInterfaceRpcService;
92 this.extnIntfs = extnIntfs;
93 this.awaiter = awaiter;
96 private void awaitForData(LogicalDatastoreType dsType, InstanceIdentifier<? extends DataObject> iid) {
97 awaiter.until(() -> singleTxdataBroker.syncReadOptional(dsType, iid).isPresent());
100 private void awaitForDataDelete(LogicalDatastoreType dsType, InstanceIdentifier<? extends DataObject> iid) {
101 awaiter.until(() -> !singleTxdataBroker.syncReadOptional(dsType, iid).isPresent());
104 public void verifyThatMcastMacTepsCreated(InstanceIdentifier<Node> torNodeId, List<String> tepIps) {
105 for (String tepIp : tepIps) {
106 awaiter.until(() -> checkForRemoteMcastMac(torNodeId, tepIp, CHECK_FOR_EXISTS));
110 public void verifyThatMcastMacTepsDeleted(InstanceIdentifier<Node> torNodeId, List<String> tepIps) {
111 for (String tepIp : tepIps) {
112 awaiter.until(() -> checkForRemoteMcastMac(torNodeId, tepIp, CHECK_FOR_DELETED));
116 private boolean checkForRemoteMcastMac(InstanceIdentifier<Node> torNodeId, String tepIp, boolean checkForExists) {
118 Node node = singleTxdataBroker.syncRead(LogicalDatastoreType.CONFIGURATION, torNodeId);
119 HwvtepGlobalAugmentation augmentation = node.augmentation(HwvtepGlobalAugmentation.class);
120 if (augmentation == null || augmentation.getRemoteMcastMacs() == null
121 || augmentation.getRemoteMcastMacs().isEmpty()) {
122 if (checkForExists) {
128 boolean remoteMcastFoundFlag = false;
129 for (RemoteMcastMacs remoteMcastMacs : augmentation.getRemoteMcastMacs()) {
130 for (LocatorSet locatorSet : remoteMcastMacs.getLocatorSet()) {
131 TpId tpId = locatorSet.getLocatorRef().getValue().firstKeyOf(TerminationPoint.class).getTpId();
132 if (tpId.getValue().contains(tepIp)) {
133 remoteMcastFoundFlag = true;
138 if (checkForExists) {
139 return remoteMcastFoundFlag == true;
141 return remoteMcastFoundFlag == false;
143 } catch (ReadFailedException e) {
148 public void verifyThatUcastCreated(InstanceIdentifier<Node> torNodeId, List<String> macs) {
149 for (String mac : macs) {
150 awaiter.until(() -> checkForRemoteUcastMac(torNodeId, mac, CHECK_FOR_EXISTS));
154 public void verifyThatUcastDeleted(InstanceIdentifier<Node> torNodeId, List<String> macs) {
155 for (String mac : macs) {
156 awaiter.until(() -> checkForRemoteUcastMac(torNodeId, mac, CHECK_FOR_DELETED));
160 public boolean checkForRemoteUcastMac(InstanceIdentifier<Node> torNodeId, String dpnMac, boolean checkForExists) {
162 Node node = singleTxdataBroker.syncRead(LogicalDatastoreType.CONFIGURATION, torNodeId);
163 HwvtepGlobalAugmentation augmentation = node.augmentation(HwvtepGlobalAugmentation.class);
164 if (augmentation == null || augmentation.getRemoteUcastMacs() == null
165 || augmentation.getRemoteUcastMacs().isEmpty()) {
166 if (checkForExists) {
172 boolean remoteUcastFoundFlag = false;
173 for (RemoteUcastMacs remoteUcastMacs : augmentation.getRemoteUcastMacs()) {
174 String mac = remoteUcastMacs.getMacEntryKey().getValue();
175 if (mac.equals(dpnMac)) {
176 remoteUcastFoundFlag = true;
180 if (checkForExists) {
181 return remoteUcastFoundFlag == true;
183 return remoteUcastFoundFlag == false;
185 } catch (ReadFailedException e) {
190 private List<Bucket> buildRemoteBcGroupBuckets(ElanInstance elanInfo,
191 List<Uint64> otherDpns,
192 List<String> otherTors,
195 throws ExecutionException, InterruptedException {
196 List<Bucket> listBucketInfo = new ArrayList<>();
197 if (otherDpns != null) {
198 for (Uint64 otherDpn : otherDpns) {
199 GetEgressActionsForInterfaceInput getEgressActInput = new GetEgressActionsForInterfaceInputBuilder()
200 .setIntfName(extnIntfs.get(dpnId + ":" + otherDpn).getInterfaceInfo().getInterfaceName())
201 .setTunnelKey(elanInfo.getElanTag()).build();
202 List<Action> actionsList =
203 odlInterfaceRpcService.getEgressActionsForInterface(getEgressActInput).get().getResult()
205 listBucketInfo.add(MDSALUtil.buildBucket(actionsList, MDSALUtil.GROUP_WEIGHT, bucketId,
206 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
212 if (otherTors != null) {
213 for (String otherTor : otherTors) {
214 GetEgressActionsForInterfaceInput getEgressActInput = new GetEgressActionsForInterfaceInputBuilder()
215 .setIntfName(extnIntfs.get(dpnId + ":" + otherTor).getInterfaceInfo().getInterfaceName())
216 .setTunnelKey(elanInfo.getSegmentationId()).build();
217 List<Action> actionsList =
218 odlInterfaceRpcService.getEgressActionsForInterface(getEgressActInput).get().getResult()
220 listBucketInfo.add(MDSALUtil.buildBucket(actionsList, MDSALUtil.GROUP_WEIGHT, bucketId,
221 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
226 return listBucketInfo;
229 private Group buildStandardElanBroadcastGroups(ElanInstance elanInfo, Uint64 dpnId, List<Uint64> otherdpns,
231 throws ExecutionException, InterruptedException {
232 List<Bucket> listBucket = new ArrayList<>();
235 Uint32 elanTag = elanInfo.getElanTag();
236 List<Action> listAction = new ArrayList<>();
237 listAction.add(new ActionGroup(ElanUtils.getElanLocalBCGId(elanTag.longValue())).buildAction(++actionKey));
238 listBucket.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
239 MDSALUtil.WATCH_GROUP));
241 listBucket.addAll(buildRemoteBcGroupBuckets(elanInfo, otherdpns, tepIps, dpnId, bucketId));
242 long groupId = ElanUtils.getElanRemoteBCGId(elanTag.longValue());
243 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
244 MDSALUtil.buildBucketLists(listBucket));
248 private boolean validateGroup(ElanInstance actualElanInstances,
250 List<Uint64> otherdpns,
252 throws ExecutionException, InterruptedException, ReadFailedException, TransactionCommitFailedException {
253 Group expected = buildStandardElanBroadcastGroups(actualElanInstances, dpnId, otherdpns, torips);
254 InstanceIdentifier<Group> grpIid = DpnNodeBuilders.createGroupIid(expected, dpnId);
255 Group actual = singleTxdataBroker.syncRead(CONFIGURATION, grpIid);
256 singleTxdataBroker.syncWrite(CONFIGURATION, grpIid, expected);
257 expected = singleTxdataBroker.syncRead(CONFIGURATION, grpIid);
259 if (BUCKETS_SIZE_MIS_MATCHED.test(expected, actual)) {
260 AssertDataObjects.assertEqualBeans(expected, actual);
263 Set<Bucket> actualBuckets = modifyBucketId(actual.getBuckets().getBucket());
264 Set<Bucket> expectedBuckets = modifyBucketId(expected.getBuckets().getBucket());
265 Set<Bucket> diff = Sets.difference(actualBuckets, expectedBuckets);
266 if (diff != null && !diff.isEmpty()) {
267 AssertDataObjects.assertEqualBeans(expected, actual);
272 private static Set<Bucket> modifyBucketId(List<Bucket> input) {
273 return input.stream()
274 .map(bucket -> new BucketBuilder(bucket).setBucketId(new BucketId(1L))
275 .withKey(new BucketKey(new BucketId(1L))).build())
276 .collect(Collectors.toSet());
279 public void verifyThatDpnGroupUpdated(Uint64 dpnId, List<Uint64> otherdpns, List<String> othertors)
280 throws ReadFailedException, TransactionCommitFailedException, ExecutionException, InterruptedException {
281 verifyDPNGroup(dpnId, otherdpns, othertors, CHECK_FOR_EXISTS);
284 public void verifyThatDpnGroupDeleted(Uint64 dpnId)
285 throws ReadFailedException, TransactionCommitFailedException, ExecutionException, InterruptedException {
286 verifyDPNGroup(dpnId, Collections.emptyList(), Collections.emptyList(), CHECK_FOR_DELETED);
289 public void verifyLocalBcGroup(Uint64 dpnId, int expectedNoBuckets)
290 throws ReadFailedException, TransactionCommitFailedException, ExecutionException, InterruptedException {
291 awaiter.until(() -> {
292 ElanInstance actualElanInstances = singleTxdataBroker.syncRead(CONFIGURATION, ELAN_IID);
293 InstanceIdentifier<Group> grpIid = buildLocalGroupIid(actualElanInstances, dpnId);
294 awaitForData(CONFIGURATION, grpIid);
295 Group localGroup = singleTxdataBroker.syncRead(CONFIGURATION, grpIid);
296 if (localGroup != null && localGroup.getBuckets() != null
297 && localGroup.getBuckets().getBucket() != null) {
298 return localGroup.getBuckets().getBucket().size() == expectedNoBuckets;
304 public void verifyThatLocalBcGroupDeleted(Uint64 dpnId)
305 throws ReadFailedException, TransactionCommitFailedException, ExecutionException, InterruptedException {
306 ElanInstance actualElanInstances = singleTxdataBroker.syncRead(CONFIGURATION, ELAN_IID);
307 InstanceIdentifier<Group> grpIid = buildLocalGroupIid(actualElanInstances, dpnId);
308 awaitForDataDelete(CONFIGURATION, grpIid);
311 public void verifyDPNGroup(Uint64 dpnId,
312 List<Uint64> otherdpns,
313 List<String> othertors,
314 boolean checkForExists)
315 throws ReadFailedException, TransactionCommitFailedException, ExecutionException, InterruptedException {
317 ElanInstance actualElanInstances = singleTxdataBroker.syncRead(CONFIGURATION, ELAN_IID);
318 InstanceIdentifier<Group> grpIid = buildGroupIid(actualElanInstances, dpnId);
320 if (checkForExists) {
321 awaitForData(LogicalDatastoreType.CONFIGURATION, grpIid);
322 validateGroup(actualElanInstances, dpnId, otherdpns, othertors);
324 awaitForDataDelete(LogicalDatastoreType.CONFIGURATION, grpIid);
328 public void verifyThatDmacFlowOfTORCreated(List<Uint64> dpns,
329 InstanceIdentifier<Node> torNodeId,
330 List<String> macs) throws ReadFailedException {
331 for (String mac : macs) {
332 for (Uint64 srcDpnId : dpns) {
333 verifyDmacFlowOfTOR(srcDpnId, torNodeId, mac, CHECK_FOR_EXISTS);
338 public void verifyThatDmacFlowOfTORDeleted(List<Uint64> dpns,
339 InstanceIdentifier<Node> torNodeId,
340 List<String> macs) throws ReadFailedException {
341 for (String mac : macs) {
342 for (Uint64 srcDpnId : dpns) {
343 verifyDmacFlowOfTOR(srcDpnId, torNodeId, mac, CHECK_FOR_DELETED);
348 public void verifyDmacFlowOfTOR(Uint64 srcDpnId,
349 InstanceIdentifier<Node> torNodeIid,
351 boolean checkForExists) throws ReadFailedException {
353 String torNodeId = torNodeIid.firstKeyOf(Node.class).getNodeId().getValue();
354 ElanInstance actualElanInstances = singleTxdataBroker.syncRead(CONFIGURATION, ELAN_IID);
355 FlowId flowId = new FlowId(
356 ElanUtils.getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE,
360 actualElanInstances.getElanTag().toJava(),
363 InstanceIdentifier<Flow> flowIid = getFlowIid(NwConstants.ELAN_DMAC_TABLE, flowId, srcDpnId);
365 if (checkForExists) {
366 awaitForData(LogicalDatastoreType.CONFIGURATION, flowIid);
368 awaitForDataDelete(LogicalDatastoreType.CONFIGURATION, flowIid);
372 public void verifyThatDmacOfOtherDpnCreated(Uint64 srcDpnId, Uint64 dpnId, List<String> dpnMacs)
373 throws ReadFailedException, InterruptedException {
374 for (String dpnMac : dpnMacs) {
375 verifyDmacFlowOfOtherDPN(srcDpnId, dpnId, dpnMac, CHECK_FOR_EXISTS);
379 public void verifyThatDmacOfOtherDPNDeleted(Uint64 srcDpnId, Uint64 dpnId, List<String> dpnMacs)
380 throws ReadFailedException, InterruptedException {
381 for (String dpnMac : dpnMacs) {
382 verifyDmacFlowOfOtherDPN(srcDpnId, dpnId, dpnMac, CHECK_FOR_DELETED);
386 private void verifyDmacFlowOfOtherDPN(Uint64 srcDpnId, Uint64 dpnId, String dpnMac, boolean createFlag)
387 throws ReadFailedException, InterruptedException {
388 InstanceIdentifier<ElanInstance> elanInstanceIid = InstanceIdentifier.builder(ElanInstances.class)
389 .child(ElanInstance.class, new ElanInstanceKey(ExpectedObjects.ELAN1)).build();
390 ElanInstance actualElanInstances = singleTxdataBroker.syncRead(CONFIGURATION, elanInstanceIid);
391 FlowId flowId = new FlowId(
392 ElanUtils.getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE,
396 actualElanInstances.getElanTag()));
397 InstanceIdentifier<Flow> flowInstanceIidDst = getFlowIid(NwConstants.ELAN_DMAC_TABLE, flowId, srcDpnId);
399 awaitForData(LogicalDatastoreType.CONFIGURATION, flowInstanceIidDst);
401 awaitForDataDelete(LogicalDatastoreType.CONFIGURATION, flowInstanceIidDst);
405 private static InstanceIdentifier<Flow> getFlowIid(short tableId, FlowId flowid, Uint64 dpnId) {
407 FlowKey flowKey = new FlowKey(new FlowId(flowid));
408 NodeId nodeId = GET_OPENFLOW_NODE_ID.apply(dpnId);
409 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node nodeDpn =
410 new NodeBuilder().setId(nodeId).withKey(new NodeKey(nodeId)).build();
411 return InstanceIdentifier.builder(Nodes.class)
412 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
413 nodeDpn.key()).augmentation(FlowCapableNode.class)
414 .child(Table.class, new TableKey(tableId)).child(Flow.class, flowKey).build();
417 private static InstanceIdentifier<Group> buildGroupIid(ElanInstance actualElanInstances, Uint64 dpnId) {
418 return DpnNodeBuilders.buildGroupInstanceIdentifier(
419 ElanUtils.getElanRemoteBCGId(actualElanInstances.getElanTag().toJava()),
420 DpnNodeBuilders.buildDpnNode(dpnId));
423 private static InstanceIdentifier<Group> buildLocalGroupIid(ElanInstance actualElanInstances, Uint64 dpnId) {
424 return DpnNodeBuilders.buildGroupInstanceIdentifier(
425 ElanUtils.getElanLocalBCGId(actualElanInstances.getElanTag().toJava()),
426 DpnNodeBuilders.buildDpnNode(dpnId));