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.mdsal.common.api.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.genius.datastoreutils.SingleTransactionDataBroker;
24 import org.opendaylight.genius.mdsalutil.MDSALUtil;
25 import org.opendaylight.genius.mdsalutil.NwConstants;
26 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
27 import org.opendaylight.genius.testutils.interfacemanager.TunnelInterfaceDetails;
28 import org.opendaylight.mdsal.binding.testutils.AssertDataObjects;
29 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
30 import org.opendaylight.mdsal.common.api.ReadFailedException;
31 import org.opendaylight.mdsal.common.api.TransactionCommitFailedException;
32 import org.opendaylight.netvirt.elan.utils.ElanConstants;
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;
66 import org.opendaylight.yangtools.yang.common.Uint32;
67 import org.opendaylight.yangtools.yang.common.Uint64;
69 public class Verifications {
71 private static final boolean CHECK_FOR_EXISTS = true;
72 private static final boolean CHECK_FOR_DELETED = false;
73 private static final Function<Uint64, NodeId> GET_OPENFLOW_NODE_ID = (dpnId) -> new NodeId("openflow:" + dpnId);
74 private static final InstanceIdentifier<ElanInstance> ELAN_IID = InstanceIdentifier
75 .builder(ElanInstances.class)
76 .child(ElanInstance.class, new ElanInstanceKey(ExpectedObjects.ELAN1))
78 private static final BiPredicate<Group, Group> BUCKETS_SIZE_MIS_MATCHED = (actual, expected) -> {
79 return !(actual.getBuckets().getBucket().size() == expected.getBuckets().getBucket().size());
82 private final SingleTransactionDataBroker singleTxdataBroker;
83 private final OdlInterfaceRpcService odlInterfaceRpcService;
84 private final Map<String, TunnelInterfaceDetails> extnIntfs;
85 private final ConditionFactory awaiter;
87 public Verifications(final SingleTransactionDataBroker singleTxdataBroker,
88 final OdlInterfaceRpcService odlInterfaceRpcService,
89 final Map<String, TunnelInterfaceDetails> extnIntfs,
90 final ConditionFactory awaiter) {
91 this.singleTxdataBroker = singleTxdataBroker;
92 this.odlInterfaceRpcService = odlInterfaceRpcService;
93 this.extnIntfs = extnIntfs;
94 this.awaiter = awaiter;
97 private void awaitForData(LogicalDatastoreType dsType, InstanceIdentifier<? extends DataObject> iid) {
98 awaiter.until(() -> singleTxdataBroker.syncReadOptional(dsType, iid).isPresent());
101 private void awaitForDataDelete(LogicalDatastoreType dsType, InstanceIdentifier<? extends DataObject> iid) {
102 awaiter.until(() -> !singleTxdataBroker.syncReadOptional(dsType, iid).isPresent());
105 public void verifyThatMcastMacTepsCreated(InstanceIdentifier<Node> torNodeId, List<String> tepIps) {
106 for (String tepIp : tepIps) {
107 awaiter.until(() -> checkForRemoteMcastMac(torNodeId, tepIp, CHECK_FOR_EXISTS));
111 public void verifyThatMcastMacTepsDeleted(InstanceIdentifier<Node> torNodeId, List<String> tepIps) {
112 for (String tepIp : tepIps) {
113 awaiter.until(() -> checkForRemoteMcastMac(torNodeId, tepIp, CHECK_FOR_DELETED));
117 private boolean checkForRemoteMcastMac(InstanceIdentifier<Node> torNodeId, String tepIp, boolean checkForExists) {
119 Node node = singleTxdataBroker.syncRead(LogicalDatastoreType.CONFIGURATION, torNodeId);
120 HwvtepGlobalAugmentation augmentation = node.augmentation(HwvtepGlobalAugmentation.class);
121 if (augmentation == null || augmentation.getRemoteMcastMacs() == null
122 || augmentation.getRemoteMcastMacs().isEmpty()) {
123 if (checkForExists) {
129 boolean remoteMcastFoundFlag = false;
130 for (RemoteMcastMacs remoteMcastMacs : augmentation.nonnullRemoteMcastMacs().values()) {
131 for (LocatorSet locatorSet : remoteMcastMacs.getLocatorSet()) {
132 TpId tpId = locatorSet.getLocatorRef().getValue().firstKeyOf(TerminationPoint.class).getTpId();
133 if (tpId.getValue().contains(tepIp)) {
134 remoteMcastFoundFlag = true;
139 if (checkForExists) {
140 return remoteMcastFoundFlag == true;
142 return remoteMcastFoundFlag == false;
144 } catch (ReadFailedException e) {
149 public void verifyThatUcastCreated(InstanceIdentifier<Node> torNodeId, List<String> macs) {
150 for (String mac : macs) {
151 awaiter.until(() -> checkForRemoteUcastMac(torNodeId, mac, CHECK_FOR_EXISTS));
155 public void verifyThatUcastDeleted(InstanceIdentifier<Node> torNodeId, List<String> macs) {
156 for (String mac : macs) {
157 awaiter.until(() -> checkForRemoteUcastMac(torNodeId, mac, CHECK_FOR_DELETED));
161 public boolean checkForRemoteUcastMac(InstanceIdentifier<Node> torNodeId, String dpnMac, boolean checkForExists) {
163 Node node = singleTxdataBroker.syncRead(LogicalDatastoreType.CONFIGURATION, torNodeId);
164 HwvtepGlobalAugmentation augmentation = node.augmentation(HwvtepGlobalAugmentation.class);
165 if (augmentation == null || augmentation.getRemoteUcastMacs() == null
166 || augmentation.getRemoteUcastMacs().isEmpty()) {
167 if (checkForExists) {
173 boolean remoteUcastFoundFlag = false;
174 for (RemoteUcastMacs remoteUcastMacs : augmentation.nonnullRemoteUcastMacs().values()) {
175 String mac = remoteUcastMacs.getMacEntryKey().getValue();
176 if (mac.equals(dpnMac)) {
177 remoteUcastFoundFlag = true;
181 if (checkForExists) {
182 return remoteUcastFoundFlag == true;
184 return remoteUcastFoundFlag == false;
186 } catch (ReadFailedException e) {
191 private List<Bucket> buildRemoteBcGroupBuckets(ElanInstance elanInfo,
192 List<Uint64> otherDpns,
193 List<String> otherTors,
196 throws ExecutionException, InterruptedException {
197 List<Bucket> listBucketInfo = new ArrayList<>();
198 if (otherDpns != null) {
199 for (Uint64 otherDpn : otherDpns) {
200 GetEgressActionsForInterfaceInput getEgressActInput = new GetEgressActionsForInterfaceInputBuilder()
201 .setIntfName(extnIntfs.get(dpnId + ":" + otherDpn).getInterfaceInfo().getInterfaceName())
202 .setTunnelKey(elanInfo.getElanTag().longValue() + ElanConstants.ELAN_TAG_ADDEND).build();
203 List<Action> actionsList =
204 new ArrayList<Action>(odlInterfaceRpcService.getEgressActionsForInterface(getEgressActInput)
205 .get().getResult().nonnullAction().values());
206 listBucketInfo.add(MDSALUtil.buildBucket(actionsList, MDSALUtil.GROUP_WEIGHT, bucketId,
207 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
213 if (otherTors != null) {
214 for (String otherTor : otherTors) {
215 GetEgressActionsForInterfaceInput getEgressActInput = new GetEgressActionsForInterfaceInputBuilder()
216 .setIntfName(extnIntfs.get(dpnId + ":" + otherTor).getInterfaceInfo().getInterfaceName())
217 .setTunnelKey(elanInfo.getSegmentationId()).build();
218 List<Action> actionsList =
219 new ArrayList<Action>(odlInterfaceRpcService.getEgressActionsForInterface(getEgressActInput)
220 .get().getResult().nonnullAction().values());
221 listBucketInfo.add(MDSALUtil.buildBucket(actionsList, MDSALUtil.GROUP_WEIGHT, bucketId,
222 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
227 return listBucketInfo;
230 private Group buildStandardElanBroadcastGroups(ElanInstance elanInfo, Uint64 dpnId, List<Uint64> otherdpns,
232 throws ExecutionException, InterruptedException {
233 List<Bucket> listBucket = new ArrayList<>();
236 Uint32 elanTag = elanInfo.getElanTag();
237 List<Action> listAction = new ArrayList<>();
238 listAction.add(new ActionGroup(ElanUtils.getElanLocalBCGId(elanTag.longValue())).buildAction(++actionKey));
239 listBucket.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
240 MDSALUtil.WATCH_GROUP));
242 listBucket.addAll(buildRemoteBcGroupBuckets(elanInfo, otherdpns, tepIps, dpnId, bucketId));
243 long groupId = ElanUtils.getElanRemoteBCGId(elanTag.longValue());
244 Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
245 MDSALUtil.buildBucketLists(listBucket));
249 private boolean validateGroup(ElanInstance actualElanInstances,
251 List<Uint64> otherdpns,
253 throws ExecutionException, InterruptedException, ReadFailedException, TransactionCommitFailedException {
254 Group expected = buildStandardElanBroadcastGroups(actualElanInstances, dpnId, otherdpns, torips);
255 InstanceIdentifier<Group> grpIid = DpnNodeBuilders.createGroupIid(expected, dpnId);
256 Group actual = singleTxdataBroker.syncRead(CONFIGURATION, grpIid);
257 singleTxdataBroker.syncWrite(CONFIGURATION, grpIid, expected);
258 expected = singleTxdataBroker.syncRead(CONFIGURATION, grpIid);
260 if (BUCKETS_SIZE_MIS_MATCHED.test(expected, actual)) {
261 AssertDataObjects.assertEqualBeans(expected, actual);
264 Set<Bucket> actualBuckets = modifyBucketId(new ArrayList<Bucket>(actual.getBuckets()
265 .nonnullBucket().values()));
266 Set<Bucket> expectedBuckets = modifyBucketId(new ArrayList<Bucket>(expected.getBuckets()
267 .nonnullBucket().values()));
268 Set<Bucket> diff = Sets.difference(actualBuckets, expectedBuckets);
269 if (diff != null && !diff.isEmpty()) {
270 AssertDataObjects.assertEqualBeans(expected, actual);
275 private static Set<Bucket> modifyBucketId(List<Bucket> input) {
276 return input.stream()
277 .map(bucket -> new BucketBuilder(bucket).setBucketId(new BucketId(1L))
278 .withKey(new BucketKey(new BucketId(1L))).build())
279 .collect(Collectors.toSet());
282 public void verifyThatDpnGroupUpdated(Uint64 dpnId, List<Uint64> otherdpns, List<String> othertors)
283 throws ReadFailedException, TransactionCommitFailedException, ExecutionException, InterruptedException {
284 verifyDPNGroup(dpnId, otherdpns, othertors, CHECK_FOR_EXISTS);
287 public void verifyThatDpnGroupDeleted(Uint64 dpnId)
288 throws ReadFailedException, TransactionCommitFailedException, ExecutionException, InterruptedException {
289 verifyDPNGroup(dpnId, Collections.emptyList(), Collections.emptyList(), CHECK_FOR_DELETED);
292 public void verifyLocalBcGroup(Uint64 dpnId, int expectedNoBuckets)
293 throws ReadFailedException, TransactionCommitFailedException, ExecutionException, InterruptedException {
294 awaiter.until(() -> {
295 ElanInstance actualElanInstances = singleTxdataBroker.syncRead(CONFIGURATION, ELAN_IID);
296 InstanceIdentifier<Group> grpIid = buildLocalGroupIid(actualElanInstances, dpnId);
297 awaitForData(CONFIGURATION, grpIid);
298 Group localGroup = singleTxdataBroker.syncRead(CONFIGURATION, grpIid);
299 if (localGroup != null && localGroup.getBuckets() != null
300 && localGroup.getBuckets().getBucket() != null) {
301 return localGroup.getBuckets().getBucket().size() == expectedNoBuckets;
307 public void verifyThatLocalBcGroupDeleted(Uint64 dpnId)
308 throws ReadFailedException, TransactionCommitFailedException, ExecutionException, InterruptedException {
309 ElanInstance actualElanInstances = singleTxdataBroker.syncRead(CONFIGURATION, ELAN_IID);
310 InstanceIdentifier<Group> grpIid = buildLocalGroupIid(actualElanInstances, dpnId);
311 awaitForDataDelete(CONFIGURATION, grpIid);
314 public void verifyDPNGroup(Uint64 dpnId,
315 List<Uint64> otherdpns,
316 List<String> othertors,
317 boolean checkForExists)
318 throws ReadFailedException, TransactionCommitFailedException, ExecutionException, InterruptedException {
320 ElanInstance actualElanInstances = singleTxdataBroker.syncRead(CONFIGURATION, ELAN_IID);
321 InstanceIdentifier<Group> grpIid = buildGroupIid(actualElanInstances, dpnId);
323 if (checkForExists) {
324 awaitForData(LogicalDatastoreType.CONFIGURATION, grpIid);
325 validateGroup(actualElanInstances, dpnId, otherdpns, othertors);
327 awaitForDataDelete(LogicalDatastoreType.CONFIGURATION, grpIid);
331 public void verifyThatDmacFlowOfTORCreated(List<Uint64> dpns,
332 InstanceIdentifier<Node> torNodeId,
333 List<String> macs) throws ReadFailedException {
334 for (String mac : macs) {
335 for (Uint64 srcDpnId : dpns) {
336 verifyDmacFlowOfTOR(srcDpnId, torNodeId, mac, CHECK_FOR_EXISTS);
341 public void verifyThatDmacFlowOfTORDeleted(List<Uint64> dpns,
342 InstanceIdentifier<Node> torNodeId,
343 List<String> macs) throws ReadFailedException {
344 for (String mac : macs) {
345 for (Uint64 srcDpnId : dpns) {
346 verifyDmacFlowOfTOR(srcDpnId, torNodeId, mac, CHECK_FOR_DELETED);
351 public void verifyDmacFlowOfTOR(Uint64 srcDpnId,
352 InstanceIdentifier<Node> torNodeIid,
354 boolean checkForExists) throws ReadFailedException {
356 String torNodeId = torNodeIid.firstKeyOf(Node.class).getNodeId().getValue();
357 ElanInstance actualElanInstances = singleTxdataBroker.syncRead(CONFIGURATION, ELAN_IID);
358 FlowId flowId = new FlowId(
359 ElanUtils.getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE,
363 actualElanInstances.getElanTag().toJava(),
366 InstanceIdentifier<Flow> flowIid = getFlowIid(NwConstants.ELAN_DMAC_TABLE, flowId, srcDpnId);
368 if (checkForExists) {
369 awaitForData(LogicalDatastoreType.CONFIGURATION, flowIid);
371 awaitForDataDelete(LogicalDatastoreType.CONFIGURATION, flowIid);
375 public void verifyThatDmacOfOtherDpnCreated(Uint64 srcDpnId, Uint64 dpnId, List<String> dpnMacs)
376 throws ReadFailedException, InterruptedException {
377 for (String dpnMac : dpnMacs) {
378 verifyDmacFlowOfOtherDPN(srcDpnId, dpnId, dpnMac, CHECK_FOR_EXISTS);
382 public void verifyThatDmacOfOtherDPNDeleted(Uint64 srcDpnId, Uint64 dpnId, List<String> dpnMacs)
383 throws ReadFailedException, InterruptedException {
384 for (String dpnMac : dpnMacs) {
385 verifyDmacFlowOfOtherDPN(srcDpnId, dpnId, dpnMac, CHECK_FOR_DELETED);
389 private void verifyDmacFlowOfOtherDPN(Uint64 srcDpnId, Uint64 dpnId, String dpnMac, boolean createFlag)
390 throws ReadFailedException, InterruptedException {
391 InstanceIdentifier<ElanInstance> elanInstanceIid = InstanceIdentifier.builder(ElanInstances.class)
392 .child(ElanInstance.class, new ElanInstanceKey(ExpectedObjects.ELAN1)).build();
393 ElanInstance actualElanInstances = singleTxdataBroker.syncRead(CONFIGURATION, elanInstanceIid);
394 FlowId flowId = new FlowId(
395 ElanUtils.getKnownDynamicmacFlowRef(actualElanInstances.getElanTag(), dpnMac));
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, Uint64 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, Uint64 dpnId) {
417 return DpnNodeBuilders.buildGroupInstanceIdentifier(
418 ElanUtils.getElanRemoteBCGId(actualElanInstances.getElanTag().toJava()),
419 DpnNodeBuilders.buildDpnNode(dpnId));
422 private static InstanceIdentifier<Group> buildLocalGroupIid(ElanInstance actualElanInstances, Uint64 dpnId) {
423 return DpnNodeBuilders.buildGroupInstanceIdentifier(
424 ElanUtils.getElanLocalBCGId(actualElanInstances.getElanTag().toJava()),
425 DpnNodeBuilders.buildDpnNode(dpnId));