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.math.BigInteger;
14 import java.util.ArrayList;
15 import java.util.Collections;
16 import java.util.List;
19 import java.util.concurrent.ExecutionException;
20 import java.util.function.BiPredicate;
21 import java.util.function.Function;
22 import java.util.stream.Collectors;
23 import org.awaitility.core.ConditionFactory;
24 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
25 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
26 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
27 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
28 import org.opendaylight.genius.mdsalutil.MDSALUtil;
29 import org.opendaylight.genius.mdsalutil.NwConstants;
30 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
31 import org.opendaylight.genius.testutils.interfacemanager.TunnelInterfaceDetails;
32 import org.opendaylight.mdsal.binding.testutils.AssertDataObjects;
33 import org.opendaylight.netvirt.elan.utils.ElanUtils;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceInput;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceInputBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.BucketId;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.BucketBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.BucketKey;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceKey;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteUcastMacs;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSet;
61 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId;
62 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
63 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
64 import org.opendaylight.yangtools.yang.binding.DataObject;
65 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
67 public class Verifications {
69 private static final boolean CHECK_FOR_EXISTS = true;
70 private static final boolean CHECK_FOR_DELETED = false;
71 private static final Function<BigInteger, NodeId> GET_OPENFLOW_NODE_ID = (dpnId) -> new NodeId("openflow:" + dpnId);
72 private static final InstanceIdentifier<ElanInstance> ELAN_IID = InstanceIdentifier
73 .builder(ElanInstances.class)
74 .child(ElanInstance.class, new ElanInstanceKey(ExpectedObjects.ELAN1))
76 private static final BiPredicate<Group, Group> BUCKETS_SIZE_MIS_MATCHED = (actual, expected) -> {
77 return !(actual.getBuckets().getBucket().size() == expected.getBuckets().getBucket().size());
80 private final SingleTransactionDataBroker singleTxdataBroker;
81 private final OdlInterfaceRpcService odlInterfaceRpcService;
82 private final Map<String, TunnelInterfaceDetails> extnIntfs;
83 private final ConditionFactory awaiter;
85 public Verifications(final SingleTransactionDataBroker singleTxdataBroker,
86 final OdlInterfaceRpcService odlInterfaceRpcService,
87 final Map<String, TunnelInterfaceDetails> extnIntfs,
88 final ConditionFactory awaiter) {
89 this.singleTxdataBroker = singleTxdataBroker;
90 this.odlInterfaceRpcService = odlInterfaceRpcService;
91 this.extnIntfs = extnIntfs;
92 this.awaiter = awaiter;
95 private void awaitForData(LogicalDatastoreType dsType, InstanceIdentifier<? extends DataObject> iid) {
96 awaiter.until(() -> singleTxdataBroker.syncReadOptional(dsType, iid).isPresent());
99 private void awaitForDataDelete(LogicalDatastoreType dsType, InstanceIdentifier<? extends DataObject> iid) {
100 awaiter.until(() -> !singleTxdataBroker.syncReadOptional(dsType, iid).isPresent());
103 public void verifyThatMcastMacTepsCreated(InstanceIdentifier<Node> torNodeId, List<String> tepIps) {
104 for (String tepIp : tepIps) {
105 awaiter.until(() -> checkForRemoteMcastMac(torNodeId, tepIp, CHECK_FOR_EXISTS));
109 public void verifyThatMcastMacTepsDeleted(InstanceIdentifier<Node> torNodeId, List<String> tepIps) {
110 for (String tepIp : tepIps) {
111 awaiter.until(() -> checkForRemoteMcastMac(torNodeId, tepIp, CHECK_FOR_DELETED));
115 private boolean checkForRemoteMcastMac(InstanceIdentifier<Node> torNodeId, String tepIp, boolean checkForExists) {
117 Node node = singleTxdataBroker.syncRead(LogicalDatastoreType.CONFIGURATION, torNodeId);
118 HwvtepGlobalAugmentation augmentation = node.augmentation(HwvtepGlobalAugmentation.class);
119 if (augmentation == null || augmentation.getRemoteMcastMacs() == null
120 || augmentation.getRemoteMcastMacs().isEmpty()) {
121 if (checkForExists) {
127 boolean remoteMcastFoundFlag = false;
128 for (RemoteMcastMacs remoteMcastMacs : augmentation.getRemoteMcastMacs()) {
129 for (LocatorSet locatorSet : remoteMcastMacs.getLocatorSet()) {
130 TpId tpId = locatorSet.getLocatorRef().getValue().firstKeyOf(TerminationPoint.class).getTpId();
131 if (tpId.getValue().contains(tepIp)) {
132 remoteMcastFoundFlag = true;
137 if (checkForExists) {
138 return remoteMcastFoundFlag == true;
140 return remoteMcastFoundFlag == false;
142 } catch (ReadFailedException e) {
147 public void verifyThatUcastCreated(InstanceIdentifier<Node> torNodeId, List<String> macs) {
148 for (String mac : macs) {
149 awaiter.until(() -> checkForRemoteUcastMac(torNodeId, mac, CHECK_FOR_EXISTS));
153 public void verifyThatUcastDeleted(InstanceIdentifier<Node> torNodeId, List<String> macs) {
154 for (String mac : macs) {
155 awaiter.until(() -> checkForRemoteUcastMac(torNodeId, mac, CHECK_FOR_DELETED));
159 public boolean checkForRemoteUcastMac(InstanceIdentifier<Node> torNodeId, String dpnMac, boolean checkForExists) {
161 Node node = singleTxdataBroker.syncRead(LogicalDatastoreType.CONFIGURATION, torNodeId);
162 HwvtepGlobalAugmentation augmentation = node.augmentation(HwvtepGlobalAugmentation.class);
163 if (augmentation == null || augmentation.getRemoteUcastMacs() == null
164 || augmentation.getRemoteUcastMacs().isEmpty()) {
165 if (checkForExists) {
171 boolean remoteUcastFoundFlag = false;
172 for (RemoteUcastMacs remoteUcastMacs : augmentation.getRemoteUcastMacs()) {
173 String mac = remoteUcastMacs.getMacEntryKey().getValue();
174 if (mac.equals(dpnMac)) {
175 remoteUcastFoundFlag = true;
179 if (checkForExists) {
180 return remoteUcastFoundFlag == true;
182 return remoteUcastFoundFlag == false;
184 } catch (ReadFailedException e) {
189 private List<Bucket> buildRemoteBcGroupBuckets(ElanInstance elanInfo,
190 List<BigInteger> otherDpns,
191 List<String> otherTors,
194 throws ExecutionException, InterruptedException {
195 List<Bucket> listBucketInfo = new ArrayList<>();
196 if (otherDpns != null) {
197 for (BigInteger otherDpn : otherDpns) {
198 GetEgressActionsForInterfaceInput getEgressActInput = new GetEgressActionsForInterfaceInputBuilder()
199 .setIntfName(extnIntfs.get(dpnId + ":" + otherDpn).getInterfaceInfo().getInterfaceName())
200 .setTunnelKey(elanInfo.getElanTag()).build();
201 List<Action> actionsList =
202 odlInterfaceRpcService.getEgressActionsForInterface(getEgressActInput).get().getResult()
204 listBucketInfo.add(MDSALUtil.buildBucket(actionsList, MDSALUtil.GROUP_WEIGHT, bucketId,
205 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
211 if (otherTors != null) {
212 for (String otherTor : otherTors) {
213 GetEgressActionsForInterfaceInput getEgressActInput = new GetEgressActionsForInterfaceInputBuilder()
214 .setIntfName(extnIntfs.get(dpnId + ":" + otherTor).getInterfaceInfo().getInterfaceName())
215 .setTunnelKey(elanInfo.getSegmentationId()).build();
216 List<Action> actionsList =
217 odlInterfaceRpcService.getEgressActionsForInterface(getEgressActInput).get().getResult()
219 listBucketInfo.add(MDSALUtil.buildBucket(actionsList, MDSALUtil.GROUP_WEIGHT, bucketId,
220 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
225 return listBucketInfo;
228 private Group buildStandardElanBroadcastGroups(ElanInstance elanInfo, BigInteger dpnId, List<BigInteger> otherdpns,
230 throws ExecutionException, InterruptedException {
231 List<Bucket> listBucket = new ArrayList<>();
234 Long elanTag = elanInfo.getElanTag();
235 List<Action> listAction = new ArrayList<>();
236 listAction.add(new ActionGroup(ElanUtils.getElanLocalBCGId(elanTag)).buildAction(++actionKey));
237 listBucket.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
238 MDSALUtil.WATCH_GROUP));
240 listBucket.addAll(buildRemoteBcGroupBuckets(elanInfo, otherdpns, tepIps, dpnId, bucketId));
241 long groupId = ElanUtils.getElanRemoteBCGId(elanTag);
242 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
243 MDSALUtil.buildBucketLists(listBucket));
247 private boolean validateGroup(ElanInstance actualElanInstances,
249 List<BigInteger> otherdpns,
251 throws ExecutionException, InterruptedException, ReadFailedException, TransactionCommitFailedException {
252 Group expected = buildStandardElanBroadcastGroups(actualElanInstances, dpnId, otherdpns, torips);
253 InstanceIdentifier<Group> grpIid = DpnNodeBuilders.createGroupIid(expected, dpnId);
254 Group actual = singleTxdataBroker.syncRead(CONFIGURATION, grpIid);
255 singleTxdataBroker.syncWrite(CONFIGURATION, grpIid, expected);
256 expected = singleTxdataBroker.syncRead(CONFIGURATION, grpIid);
258 if (BUCKETS_SIZE_MIS_MATCHED.test(expected, actual)) {
259 AssertDataObjects.assertEqualBeans(expected, actual);
262 Set<Bucket> actualBuckets = modifyBucketId(actual.getBuckets().getBucket());
263 Set<Bucket> expectedBuckets = modifyBucketId(expected.getBuckets().getBucket());
264 Set<Bucket> diff = Sets.difference(actualBuckets, expectedBuckets);
265 if (diff != null && !diff.isEmpty()) {
266 AssertDataObjects.assertEqualBeans(expected, actual);
271 private static Set<Bucket> modifyBucketId(List<Bucket> input) {
272 return input.stream()
273 .map(bucket -> new BucketBuilder(bucket).setBucketId(new BucketId(1L))
274 .withKey(new BucketKey(new BucketId(1L))).build())
275 .collect(Collectors.toSet());
278 public void verifyThatDpnGroupUpdated(BigInteger dpnId, List<BigInteger> otherdpns, List<String> othertors)
279 throws ReadFailedException, TransactionCommitFailedException, ExecutionException, InterruptedException {
280 verifyDPNGroup(dpnId, otherdpns, othertors, CHECK_FOR_EXISTS);
283 public void verifyThatDpnGroupDeleted(BigInteger dpnId)
284 throws ReadFailedException, TransactionCommitFailedException, ExecutionException, InterruptedException {
285 verifyDPNGroup(dpnId, Collections.emptyList(), Collections.emptyList(), CHECK_FOR_DELETED);
288 public void verifyLocalBcGroup(BigInteger dpnId, int expectedNoBuckets)
289 throws ReadFailedException, TransactionCommitFailedException, ExecutionException, InterruptedException {
290 awaiter.until(() -> {
291 ElanInstance actualElanInstances = singleTxdataBroker.syncRead(CONFIGURATION, ELAN_IID);
292 InstanceIdentifier<Group> grpIid = buildLocalGroupIid(actualElanInstances, dpnId);
293 awaitForData(CONFIGURATION, grpIid);
294 Group localGroup = singleTxdataBroker.syncRead(CONFIGURATION, grpIid);
295 if (localGroup != null && localGroup.getBuckets() != null
296 && localGroup.getBuckets().getBucket() != null) {
297 return localGroup.getBuckets().getBucket().size() == expectedNoBuckets;
303 public void verifyThatLocalBcGroupDeleted(BigInteger dpnId)
304 throws ReadFailedException, TransactionCommitFailedException, ExecutionException, InterruptedException {
305 ElanInstance actualElanInstances = singleTxdataBroker.syncRead(CONFIGURATION, ELAN_IID);
306 InstanceIdentifier<Group> grpIid = buildLocalGroupIid(actualElanInstances, dpnId);
307 awaitForDataDelete(CONFIGURATION, grpIid);
310 public void verifyDPNGroup(BigInteger dpnId,
311 List<BigInteger> otherdpns,
312 List<String> othertors,
313 boolean checkForExists)
314 throws ReadFailedException, TransactionCommitFailedException, ExecutionException, InterruptedException {
316 ElanInstance actualElanInstances = singleTxdataBroker.syncRead(CONFIGURATION, ELAN_IID);
317 InstanceIdentifier<Group> grpIid = buildGroupIid(actualElanInstances, dpnId);
319 if (checkForExists) {
320 awaitForData(LogicalDatastoreType.CONFIGURATION, grpIid);
321 validateGroup(actualElanInstances, dpnId, otherdpns, othertors);
323 awaitForDataDelete(LogicalDatastoreType.CONFIGURATION, grpIid);
327 public void verifyThatDmacFlowOfTORCreated(List<BigInteger> dpns,
328 InstanceIdentifier<Node> torNodeId,
329 List<String> macs) throws ReadFailedException {
330 for (String mac : macs) {
331 for (BigInteger srcDpnId : dpns) {
332 verifyDmacFlowOfTOR(srcDpnId, torNodeId, mac, CHECK_FOR_EXISTS);
337 public void verifyThatDmacFlowOfTORDeleted(List<BigInteger> dpns,
338 InstanceIdentifier<Node> torNodeId,
339 List<String> macs) throws ReadFailedException {
340 for (String mac : macs) {
341 for (BigInteger srcDpnId : dpns) {
342 verifyDmacFlowOfTOR(srcDpnId, torNodeId, mac, CHECK_FOR_DELETED);
347 public void verifyDmacFlowOfTOR(BigInteger srcDpnId,
348 InstanceIdentifier<Node> torNodeIid,
350 boolean checkForExists) throws ReadFailedException {
352 String torNodeId = torNodeIid.firstKeyOf(Node.class).getNodeId().getValue();
353 ElanInstance actualElanInstances = singleTxdataBroker.syncRead(CONFIGURATION, ELAN_IID);
354 FlowId flowId = new FlowId(
355 ElanUtils.getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE,
359 actualElanInstances.getElanTag(),
362 InstanceIdentifier<Flow> flowIid = getFlowIid(NwConstants.ELAN_DMAC_TABLE, flowId, srcDpnId);
364 if (checkForExists) {
365 awaitForData(LogicalDatastoreType.CONFIGURATION, flowIid);
367 awaitForDataDelete(LogicalDatastoreType.CONFIGURATION, flowIid);
371 public void verifyThatDmacOfOtherDpnCreated(BigInteger srcDpnId, BigInteger dpnId, List<String> dpnMacs)
372 throws ReadFailedException, InterruptedException {
373 for (String dpnMac : dpnMacs) {
374 verifyDmacFlowOfOtherDPN(srcDpnId, dpnId, dpnMac, CHECK_FOR_EXISTS);
378 public void verifyThatDmacOfOtherDPNDeleted(BigInteger srcDpnId, BigInteger dpnId, List<String> dpnMacs)
379 throws ReadFailedException, InterruptedException {
380 for (String dpnMac : dpnMacs) {
381 verifyDmacFlowOfOtherDPN(srcDpnId, dpnId, dpnMac, CHECK_FOR_DELETED);
385 private void verifyDmacFlowOfOtherDPN(BigInteger srcDpnId, BigInteger dpnId, String dpnMac, boolean createFlag)
386 throws ReadFailedException, InterruptedException {
387 InstanceIdentifier<ElanInstance> elanInstanceIid = InstanceIdentifier.builder(ElanInstances.class)
388 .child(ElanInstance.class, new ElanInstanceKey(ExpectedObjects.ELAN1)).build();
389 ElanInstance actualElanInstances = singleTxdataBroker.syncRead(CONFIGURATION, elanInstanceIid);
390 FlowId flowId = new FlowId(
391 ElanUtils.getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE,
395 actualElanInstances.getElanTag()));
396 InstanceIdentifier<Flow> flowInstanceIidDst = getFlowIid(NwConstants.ELAN_DMAC_TABLE, flowId, srcDpnId);
398 awaitForData(LogicalDatastoreType.CONFIGURATION, flowInstanceIidDst);
400 awaitForDataDelete(LogicalDatastoreType.CONFIGURATION, flowInstanceIidDst);
404 private static InstanceIdentifier<Flow> getFlowIid(short tableId, FlowId flowid, BigInteger dpnId) {
406 FlowKey flowKey = new FlowKey(new FlowId(flowid));
407 NodeId nodeId = GET_OPENFLOW_NODE_ID.apply(dpnId);
408 org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node nodeDpn =
409 new NodeBuilder().setId(nodeId).withKey(new NodeKey(nodeId)).build();
410 return InstanceIdentifier.builder(Nodes.class)
411 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
412 nodeDpn.key()).augmentation(FlowCapableNode.class)
413 .child(Table.class, new TableKey(tableId)).child(Flow.class, flowKey).build();
416 private static InstanceIdentifier<Group> buildGroupIid(ElanInstance actualElanInstances, BigInteger dpnId) {
417 return DpnNodeBuilders.buildGroupInstanceIdentifier(
418 ElanUtils.getElanRemoteBCGId(actualElanInstances.getElanTag()), DpnNodeBuilders.buildDpnNode(dpnId));
421 private static InstanceIdentifier<Group> buildLocalGroupIid(ElanInstance actualElanInstances, BigInteger dpnId) {
422 return DpnNodeBuilders.buildGroupInstanceIdentifier(
423 ElanUtils.getElanLocalBCGId(actualElanInstances.getElanTag()), DpnNodeBuilders.buildDpnNode(dpnId));