blob: 00ad506df542899fc34d0c04313c688ac9c8de73 [file] [log] [blame]
/*
* Copyright 2018-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.net.pi.impl;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.testing.EqualsTester;
import org.junit.Assert;
import org.junit.Test;
import org.onosproject.TestApplicationId;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.GroupId;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.group.DefaultGroup;
import org.onosproject.net.group.DefaultGroupBucket;
import org.onosproject.net.group.DefaultGroupDescription;
import org.onosproject.net.group.DefaultGroupKey;
import org.onosproject.net.group.Group;
import org.onosproject.net.group.GroupBucket;
import org.onosproject.net.group.GroupBuckets;
import org.onosproject.net.group.GroupDescription;
import org.onosproject.net.group.GroupKey;
import org.onosproject.net.pi.runtime.PiCloneSessionEntry;
import org.onosproject.net.pi.runtime.PiMulticastGroupEntry;
import org.onosproject.net.pi.runtime.PiPreEntry;
import org.onosproject.net.pi.runtime.PiPreReplica;
import org.onosproject.net.pi.service.PiTranslationException;
import java.util.List;
import java.util.Set;
import static org.onosproject.net.group.GroupDescription.Type.ALL;
import static org.onosproject.net.group.GroupDescription.Type.CLONE;
/**
* Test for {@link PiReplicationGroupTranslatorImpl}.
*/
public class PiReplicationGroupTranslatorImplTest {
private static final DeviceId DEVICE_ID = DeviceId.deviceId("device:dummy:1");
private static final ApplicationId APP_ID = TestApplicationId.create("dummy");
private static final int ENTRY_ID = 99;
private static final GroupId GROUP_ID = GroupId.valueOf(ENTRY_ID);
private static final GroupKey GROUP_KEY = new DefaultGroupKey(
String.valueOf(GROUP_ID.id()).getBytes());
private static final int TRUNCATE_MAC_LEN = 1400;
private static final List<GroupBucket> BUCKET_LIST = ImmutableList.of(
allOutputBucket(1),
allOutputBucket(2),
allOutputBucket(3));
private static final List<GroupBucket> BUCKET_LIST_2 = ImmutableList.of(
allOutputBucket(1),
allOutputBucket(2),
allOutputBucket(2),
allOutputBucket(3),
allOutputBucket(3));
private static final List<GroupBucket> CLONE_BUCKET_LIST = ImmutableList.of(
cloneOutputBucket(1),
cloneOutputBucket(2),
cloneOutputBucket(3));
private static final List<GroupBucket> CLONE_BUCKET_LIST_2 = ImmutableList.of(
cloneOutputBucket(1, TRUNCATE_MAC_LEN),
cloneOutputBucket(2, TRUNCATE_MAC_LEN),
cloneOutputBucket(3, TRUNCATE_MAC_LEN));
private static final List<GroupBucket> INVALID_BUCKET_LIST = ImmutableList.of(
DefaultGroupBucket.createAllGroupBucket(
DefaultTrafficTreatment.emptyTreatment()
)
);
// This is invalid since we can only use truncate instruction in a clone group.
private static final List<GroupBucket> INVALID_BUCKET_LIST_2 = ImmutableList.of(
DefaultGroupBucket.createAllGroupBucket(
DefaultTrafficTreatment.builder()
.setOutput(PortNumber.portNumber(1))
.truncate(TRUNCATE_MAC_LEN)
.build()
)
);
// Unsupported instruction.
private static final List<GroupBucket> INVALID_BUCKET_LIST_3 = ImmutableList.of(
DefaultGroupBucket.createAllGroupBucket(
DefaultTrafficTreatment.builder()
.setOutput(PortNumber.portNumber(1))
.popVlan()
.build()
)
);
private static final List<GroupBucket> INVALID_CLONE_BUCKET_LIST = ImmutableList.of(
DefaultGroupBucket.createCloneGroupBucket(
DefaultTrafficTreatment.emptyTreatment()
)
);
// This is invalid since all truncate instruction must be the same.
private static final List<GroupBucket> INVALID_CLONE_BUCKET_LIST_2 = ImmutableList.of(
cloneOutputBucket(1, TRUNCATE_MAC_LEN),
cloneOutputBucket(2, TRUNCATE_MAC_LEN + 1)
);
// This is invalid since only one truncate instruction is allowed per bucket.
private static final List<GroupBucket> INVALID_CLONE_BUCKET_LIST_3 = ImmutableList.of(
DefaultGroupBucket.createCloneGroupBucket(
DefaultTrafficTreatment.builder()
.setOutput(PortNumber.portNumber(1))
.truncate(TRUNCATE_MAC_LEN)
.truncate(TRUNCATE_MAC_LEN)
.build()
)
);
// Inconsistent truncate instructions.
private static final List<GroupBucket> INVALID_CLONE_BUCKET_LIST_4 = ImmutableList.of(
cloneOutputBucket(1, TRUNCATE_MAC_LEN),
cloneOutputBucket(2, TRUNCATE_MAC_LEN),
cloneOutputBucket(3)
);
private static final Set<PiPreReplica> REPLICAS = ImmutableSet.of(
new PiPreReplica(PortNumber.portNumber(1), 0),
new PiPreReplica(PortNumber.portNumber(2), 0),
new PiPreReplica(PortNumber.portNumber(3), 0));
private static final Set<PiPreReplica> REPLICAS_2 = ImmutableSet.of(
new PiPreReplica(PortNumber.portNumber(1), 0),
new PiPreReplica(PortNumber.portNumber(2), 0),
new PiPreReplica(PortNumber.portNumber(2), 1),
new PiPreReplica(PortNumber.portNumber(3), 0),
new PiPreReplica(PortNumber.portNumber(3), 1));
private static final PiMulticastGroupEntry PI_MULTICAST_GROUP =
PiMulticastGroupEntry.builder()
.withGroupId(GROUP_ID.id())
.addReplicas(REPLICAS)
.build();
private static final PiMulticastGroupEntry PI_MULTICAST_GROUP_2 =
PiMulticastGroupEntry.builder()
.withGroupId(GROUP_ID.id())
.addReplicas(REPLICAS_2)
.build();
private static final PiCloneSessionEntry PI_CLONE_SESSION_ENTRY =
PiCloneSessionEntry.builder()
.withSessionId(ENTRY_ID)
.addReplicas(REPLICAS)
.build();
private static final PiCloneSessionEntry PI_CLONE_SESSION_ENTRY_2 =
PiCloneSessionEntry.builder()
.withSessionId(ENTRY_ID)
.addReplicas(REPLICAS)
.withMaxPacketLengthBytes(TRUNCATE_MAC_LEN)
.build();
private static final Group ALL_GROUP = createGroup(BUCKET_LIST, ALL);
private static final Group ALL_GROUP_2 = createGroup(BUCKET_LIST_2, ALL);
private static final Group CLONE_GROUP = createGroup(CLONE_BUCKET_LIST, CLONE);
private static final Group CLONE_GROUP_2 = createGroup(CLONE_BUCKET_LIST_2, CLONE);
private static final Group INVALID_ALL_GROUP = createGroup(INVALID_BUCKET_LIST, ALL);
private static final Group INVALID_ALL_GROUP_2 = createGroup(INVALID_BUCKET_LIST_2, ALL);
private static final Group INVALID_ALL_GROUP_3 = createGroup(INVALID_BUCKET_LIST_3, ALL);
private static final Group INVALID_CLONE_GROUP = createGroup(INVALID_CLONE_BUCKET_LIST, CLONE);
private static final Group INVALID_CLONE_GROUP_2 = createGroup(INVALID_CLONE_BUCKET_LIST_2, CLONE);
private static final Group INVALID_CLONE_GROUP_3 = createGroup(INVALID_CLONE_BUCKET_LIST_3, CLONE);
private static final Group INVALID_CLONE_GROUP_4 = createGroup(INVALID_CLONE_BUCKET_LIST_4, CLONE);
private static GroupBucket allOutputBucket(int portNum) {
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.setOutput(PortNumber.portNumber(portNum))
.build();
return DefaultGroupBucket.createAllGroupBucket(treatment);
}
private static GroupBucket cloneOutputBucket(int portNum) {
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.setOutput(PortNumber.portNumber(portNum))
.build();
return DefaultGroupBucket.createCloneGroupBucket(treatment);
}
private static GroupBucket cloneOutputBucket(int portNum, int truncateMaxLen) {
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.setOutput(PortNumber.portNumber(portNum))
.truncate(truncateMaxLen)
.build();
return DefaultGroupBucket.createCloneGroupBucket(treatment);
}
private static Group createGroup(List<GroupBucket> bucketList, GroupDescription.Type type) {
final GroupBuckets buckets = new GroupBuckets(bucketList);
final GroupDescription groupDesc = new DefaultGroupDescription(
DEVICE_ID, type, buckets, GROUP_KEY, GROUP_ID.id(), APP_ID);
return new DefaultGroup(GROUP_ID, groupDesc);
}
@Test
public void testTranslatePreGroups() throws Exception {
PiPreEntry multicastGroup = PiReplicationGroupTranslatorImpl
.translate(ALL_GROUP, null, null);
PiPreEntry multicastGroup2 = PiReplicationGroupTranslatorImpl
.translate(ALL_GROUP_2, null, null);
PiPreEntry cloneSessionEntry = PiReplicationGroupTranslatorImpl
.translate(CLONE_GROUP, null, null);
PiPreEntry cloneSessionEntry2 = PiReplicationGroupTranslatorImpl
.translate(CLONE_GROUP_2, null, null);
new EqualsTester()
.addEqualityGroup(multicastGroup, PI_MULTICAST_GROUP)
.addEqualityGroup(multicastGroup2, PI_MULTICAST_GROUP_2)
.addEqualityGroup(cloneSessionEntry, PI_CLONE_SESSION_ENTRY)
.addEqualityGroup(cloneSessionEntry2, PI_CLONE_SESSION_ENTRY_2)
.testEquals();
}
@Test
public void testInvalidPreGroups() {
try {
PiReplicationGroupTranslatorImpl
.translate(INVALID_ALL_GROUP, null, null);
Assert.fail("Did not get expected exception.");
} catch (PiTranslationException ex) {
Assert.assertEquals("support only groups with just one OUTPUT instruction per bucket", ex.getMessage());
}
try {
PiReplicationGroupTranslatorImpl
.translate(INVALID_ALL_GROUP_2, null, null);
Assert.fail("Did not get expected exception.");
} catch (PiTranslationException ex) {
Assert.assertEquals("only CLONE group support truncate instruction", ex.getMessage());
}
try {
PiReplicationGroupTranslatorImpl
.translate(INVALID_ALL_GROUP_3, null, null);
Assert.fail("Did not get expected exception.");
} catch (PiTranslationException ex) {
Assert.assertEquals("bucket contains unsupported instruction(s)", ex.getMessage());
}
try {
PiReplicationGroupTranslatorImpl
.translate(INVALID_CLONE_GROUP, null, null);
Assert.fail("Did not get expected exception.");
} catch (PiTranslationException ex) {
Assert.assertEquals("support only groups with just one OUTPUT instruction per bucket", ex.getMessage());
}
try {
PiReplicationGroupTranslatorImpl
.translate(INVALID_CLONE_GROUP_2, null, null);
Assert.fail("Did not get expected exception.");
} catch (PiTranslationException ex) {
Assert.assertEquals("all TRUNCATE instruction must be the same in a CLONE group", ex.getMessage());
}
try {
PiReplicationGroupTranslatorImpl
.translate(INVALID_CLONE_GROUP_3, null, null);
Assert.fail("Did not get expected exception.");
} catch (PiTranslationException ex) {
Assert.assertEquals("support only groups with just one TRUNCATE instruction per bucket", ex.getMessage());
}
try {
PiReplicationGroupTranslatorImpl
.translate(INVALID_CLONE_GROUP_4, null, null);
Assert.fail("Did not get expected exception.");
} catch (PiTranslationException ex) {
Assert.assertEquals("all TRUNCATE instruction must be the same in a CLONE group", ex.getMessage());
}
}
}