use of org.onosproject.net.flowobjective.NextObjective in project fabric-tna by stratum.
the class NextObjectiveTranslatorTest method testBroadcastOutput.
/**
* Test program output group for Broadcast table.
*/
@Test
public void testBroadcastOutput() throws FabricPipelinerException {
TrafficTreatment treatment1 = DefaultTrafficTreatment.builder().setOutput(PORT_1).build();
TrafficTreatment treatment2 = DefaultTrafficTreatment.builder().popVlan().setOutput(PORT_2).build();
NextObjective nextObjective = DefaultNextObjective.builder().withId(NEXT_ID_1).withPriority(PRIORITY).addTreatment(treatment1).addTreatment(treatment2).withMeta(VLAN_META).withType(NextObjective.Type.BROADCAST).makePermanent().fromApp(APP_ID).add();
ObjectiveTranslation actualTranslation = translatorHashed.doTranslate(nextObjective);
// Should generate 3 flows:
// - Multicast table flow that matches on next-id and set multicast group (1)
// - Egress VLAN pop handling for treatment2 (0)
// - Next VLAN flow (2)
// And 2 groups:
// - Multicast group
// Expected multicast table flow rule.
PiCriterion nextIdCriterion = PiCriterion.builder().matchExact(P4InfoConstants.HDR_NEXT_ID, NEXT_ID_1).build();
TrafficSelector nextIdSelector = DefaultTrafficSelector.builder().matchPi(nextIdCriterion).build();
PiAction setMcGroupAction = PiAction.builder().withId(P4InfoConstants.FABRIC_INGRESS_NEXT_SET_MCAST_GROUP_ID).withParameter(new PiActionParam(P4InfoConstants.GROUP_ID, NEXT_ID_1)).build();
TrafficTreatment treatment = DefaultTrafficTreatment.builder().piTableAction(setMcGroupAction).build();
FlowRule expectedHashedFlowRule = DefaultFlowRule.builder().forDevice(DEVICE_ID).fromApp(APP_ID).makePermanent().withPriority(nextObjective.priority()).forTable(P4InfoConstants.FABRIC_INGRESS_NEXT_MULTICAST).withSelector(nextIdSelector).withTreatment(treatment).build();
// Expected egress VLAN_PUSH flow rule.
PiCriterion egressVlanTableMatch = PiCriterion.builder().matchExact(P4InfoConstants.HDR_EG_PORT, PORT_1.toLong()).build();
TrafficSelector selectorForEgressVlan = DefaultTrafficSelector.builder().matchPi(egressVlanTableMatch).matchVlanId(VLAN_100).build();
PiAction piActionForEgressVlan = PiAction.builder().withId(P4InfoConstants.FABRIC_EGRESS_EGRESS_NEXT_PUSH_VLAN).build();
TrafficTreatment treatmentForEgressVlan = DefaultTrafficTreatment.builder().piTableAction(piActionForEgressVlan).build();
FlowRule expectedEgressVlanPushRule = DefaultFlowRule.builder().withSelector(selectorForEgressVlan).withTreatment(treatmentForEgressVlan).forTable(P4InfoConstants.FABRIC_EGRESS_EGRESS_NEXT_EGRESS_VLAN).makePermanent().withPriority(nextObjective.priority()).forDevice(DEVICE_ID).fromApp(APP_ID).build();
// Expected egress VLAN POP flow rule.
egressVlanTableMatch = PiCriterion.builder().matchExact(P4InfoConstants.HDR_EG_PORT, PORT_2.toLong()).build();
selectorForEgressVlan = DefaultTrafficSelector.builder().matchPi(egressVlanTableMatch).matchVlanId(VLAN_100).build();
piActionForEgressVlan = PiAction.builder().withId(P4InfoConstants.FABRIC_EGRESS_EGRESS_NEXT_POP_VLAN).build();
treatmentForEgressVlan = DefaultTrafficTreatment.builder().piTableAction(piActionForEgressVlan).build();
FlowRule expectedEgressVlanPopRule = DefaultFlowRule.builder().withSelector(selectorForEgressVlan).withTreatment(treatmentForEgressVlan).forTable(P4InfoConstants.FABRIC_EGRESS_EGRESS_NEXT_EGRESS_VLAN).makePermanent().withPriority(nextObjective.priority()).forDevice(DEVICE_ID).fromApp(APP_ID).build();
// Expected ALL group.
TrafficTreatment allGroupTreatment1 = DefaultTrafficTreatment.builder().setOutput(PORT_1).build();
TrafficTreatment allGroupTreatment2 = DefaultTrafficTreatment.builder().setOutput(PORT_2).build();
List<TrafficTreatment> allTreatments = ImmutableList.of(allGroupTreatment1, allGroupTreatment2);
List<GroupBucket> allBuckets = allTreatments.stream().map(DefaultGroupBucket::createAllGroupBucket).collect(Collectors.toList());
GroupBuckets allGroupBuckets = new GroupBuckets(allBuckets);
GroupKey allGroupKey = new DefaultGroupKey(FabricUtils.KRYO.serialize(NEXT_ID_1));
GroupDescription expectedAllGroup = new DefaultGroupDescription(DEVICE_ID, GroupDescription.Type.ALL, allGroupBuckets, allGroupKey, NEXT_ID_1, APP_ID);
ObjectiveTranslation expectedTranslation = ObjectiveTranslation.builder().addFlowRule(expectedHashedFlowRule).addFlowRule(vlanMetaFlowRule).addFlowRule(expectedEgressVlanPushRule).addFlowRule(expectedEgressVlanPopRule).addGroup(expectedAllGroup).build();
assertEquals(expectedTranslation, actualTranslation);
}
use of org.onosproject.net.flowobjective.NextObjective in project trellis-control by opennetworkinglab.
the class McastHandler method getSinks.
/**
* Gets sink(s) of given multicast group.
*
* @param mcastIp multicast IP
* @return set of connect point or empty set if not found
*/
private Set<ConnectPoint> getSinks(IpAddress mcastIp, DeviceId device, ConnectPoint source) {
McastPathStoreKey pathStoreKey = new McastPathStoreKey(mcastIp, source);
Collection<? extends List<Link>> storedPaths = Versioned.valueOrElse(mcastPathStore.get(pathStoreKey), Lists.newArrayList());
VlanId assignedVlan = mcastUtils.assignedVlan(device.equals(source.deviceId()) ? source : null);
McastStoreKey mcastStoreKey = new McastStoreKey(mcastIp, device, assignedVlan);
NextObjective nextObjective = Versioned.valueOrNull(mcastNextObjStore.get(mcastStoreKey));
ImmutableSet.Builder<ConnectPoint> cpBuilder = ImmutableSet.builder();
if (nextObjective != null) {
Set<PortNumber> outputPorts = mcastUtils.getPorts(nextObjective.next());
outputPorts.forEach(portNumber -> cpBuilder.add(new ConnectPoint(device, portNumber)));
}
Set<ConnectPoint> egressCp = cpBuilder.build();
return egressCp.stream().filter(connectPoint -> !mcastUtils.isInfraPort(connectPoint, storedPaths)).collect(Collectors.toSet());
}
use of org.onosproject.net.flowobjective.NextObjective in project trellis-control by opennetworkinglab.
the class McastHandler method isSinkForGroup.
/**
* Verify if a given connect point is sink for this group.
*
* @param mcastIp group address
* @param connectPoint connect point to be verified
* @param source source connect point
* @return true if the connect point is sink of the group
*/
private boolean isSinkForGroup(IpAddress mcastIp, ConnectPoint connectPoint, ConnectPoint source) {
VlanId assignedVlan = mcastUtils.assignedVlan(connectPoint.deviceId().equals(source.deviceId()) ? source : null);
McastStoreKey mcastStoreKey = new McastStoreKey(mcastIp, connectPoint.deviceId(), assignedVlan);
if (!mcastNextObjStore.containsKey(mcastStoreKey)) {
return false;
}
NextObjective mcastNext = mcastNextObjStore.get(mcastStoreKey).value();
return mcastUtils.getPorts(mcastNext.next()).contains(connectPoint.port());
}
use of org.onosproject.net.flowobjective.NextObjective in project trellis-control by opennetworkinglab.
the class McastHandler method removePortFromDevice.
/**
* Removes a port from given multicast group on given device.
* This involves the update of L3 multicast group and multicast routing
* table entry.
*
* @param deviceId device ID
* @param port port to be added
* @param mcastIp multicast group
* @param assignedVlan assigned VLAN ID
* @return true if this is the last sink on this device
*/
private boolean removePortFromDevice(DeviceId deviceId, PortNumber port, IpAddress mcastIp, VlanId assignedVlan) {
// TODO trace
log.info("Removing {} on {}/{} and vlan {}", mcastIp, deviceId, port, assignedVlan);
McastStoreKey mcastStoreKey = new McastStoreKey(mcastIp, deviceId, assignedVlan);
// This device is not serving this multicast group
if (!mcastNextObjStore.containsKey(mcastStoreKey)) {
return true;
}
NextObjective nextObj = mcastNextObjStore.get(mcastStoreKey).value();
Set<PortNumber> existingPorts = mcastUtils.getPorts(nextObj.next());
// This port does not serve this multicast group
if (!existingPorts.contains(port)) {
if (!existingPorts.isEmpty()) {
log.debug("{} is not serving {} on port {}. Abort.", deviceId, mcastIp, port);
return false;
}
return true;
}
// Copy and modify the ImmutableSet
existingPorts = Sets.newHashSet(existingPorts);
existingPorts.remove(port);
NextObjective newNextObj;
ObjectiveContext context;
ForwardingObjective fwdObj;
if (existingPorts.isEmpty()) {
context = new DefaultObjectiveContext((objective) -> log.debug("Successfully remove {} on {}/{}, vlan {}", mcastIp, deviceId, port.toLong(), assignedVlan), (objective, error) -> log.warn("Failed to remove {} on {}/{}, vlan {}: {}", mcastIp, deviceId, port.toLong(), assignedVlan, error));
fwdObj = mcastUtils.fwdObjBuilder(mcastIp, assignedVlan, nextObj.id()).remove(context);
if (!srManager.deviceConfiguration().isConfigured(deviceId)) {
log.debug("skip forward flowobjective removal for device: {}", deviceId);
} else {
srManager.flowObjectiveService.forward(deviceId, fwdObj);
}
mcastNextObjStore.remove(mcastStoreKey);
} else {
// Here we store the next objective with the remaining port
newNextObj = mcastUtils.nextObjBuilder(mcastIp, assignedVlan, existingPorts, nextObj.id()).removeFromExisting();
mcastNextObjStore.put(mcastStoreKey, newNextObj);
// Let's modify the next objective removing the bucket
newNextObj = mcastUtils.nextObjBuilder(mcastIp, assignedVlan, ImmutableSet.of(port), nextObj.id()).removeFromExisting();
if (!srManager.deviceConfiguration().isConfigured(deviceId)) {
log.debug("skip next flowobjective update for device: {}", deviceId);
} else {
// no need to update the flow here since we have updated the next objective + group
// the existing flow will keep pointing to the updated nextobj
srManager.flowObjectiveService.next(deviceId, newNextObj);
}
}
return existingPorts.isEmpty();
}
use of org.onosproject.net.flowobjective.NextObjective in project trellis-control by opennetworkinglab.
the class McastHandler method addPortToDevice.
/**
* Adds a port to given multicast group on given device. This involves the
* update of L3 multicast group and multicast routing table entry.
*
* @param deviceId device ID
* @param port port to be added
* @param mcastIp multicast group
* @param assignedVlan assigned VLAN ID
*/
private void addPortToDevice(DeviceId deviceId, PortNumber port, IpAddress mcastIp, VlanId assignedVlan) {
// TODO trace
log.info("Adding {} on {}/{} and vlan {}", mcastIp, deviceId, port, assignedVlan);
McastStoreKey mcastStoreKey = new McastStoreKey(mcastIp, deviceId, assignedVlan);
ImmutableSet.Builder<PortNumber> portBuilder = ImmutableSet.builder();
NextObjective newNextObj;
if (!mcastNextObjStore.containsKey(mcastStoreKey)) {
// First time someone request this mcast group via this device
portBuilder.add(port);
// New nextObj
if (!srManager.deviceConfiguration().isConfigured(deviceId)) {
log.debug("Passing 0 as nextId for unconfigured device {}", deviceId);
newNextObj = mcastUtils.nextObjBuilder(mcastIp, assignedVlan, portBuilder.build(), 0).add();
} else {
newNextObj = mcastUtils.nextObjBuilder(mcastIp, assignedVlan, portBuilder.build(), null).add();
}
// Store the new port
mcastNextObjStore.put(mcastStoreKey, newNextObj);
// Create, store and apply the new nextObj and fwdObj
ObjectiveContext context = new DefaultObjectiveContext((objective) -> log.debug("Successfully add {} on {}/{}, vlan {}", mcastIp, deviceId, port.toLong(), assignedVlan), (objective, error) -> {
log.warn("Failed to add {} on {}/{}, vlan {}: {}", mcastIp, deviceId, port.toLong(), assignedVlan, error);
// Schedule the removal using directly the key
mcastWorker.execute(() -> mcastNextObjStore.remove(mcastStoreKey));
});
ForwardingObjective fwdObj = mcastUtils.fwdObjBuilder(mcastIp, assignedVlan, newNextObj.id()).add(context);
if (!srManager.deviceConfiguration().isConfigured(deviceId)) {
log.debug("skip next and forward flowobjective addition for device: {}", deviceId);
} else {
srManager.flowObjectiveService.next(deviceId, newNextObj);
srManager.flowObjectiveService.forward(deviceId, fwdObj);
}
} else {
// This device already serves some subscribers of this mcast group
NextObjective nextObj = mcastNextObjStore.get(mcastStoreKey).value();
// Stop if the port is already in the nextobj
Set<PortNumber> existingPorts = mcastUtils.getPorts(nextObj.next());
if (existingPorts.contains(port)) {
log.debug("Port {}/{} already exists for {}. Abort", deviceId, port, mcastIp);
return;
}
// Let's add the port and reuse the previous one
portBuilder.addAll(existingPorts).add(port);
// Reuse previous nextObj
newNextObj = mcastUtils.nextObjBuilder(mcastIp, assignedVlan, portBuilder.build(), nextObj.id()).addToExisting();
// Store the final next objective and send only the difference to the driver
mcastNextObjStore.put(mcastStoreKey, newNextObj);
// Add just the new port
portBuilder = ImmutableSet.builder();
portBuilder.add(port);
newNextObj = mcastUtils.nextObjBuilder(mcastIp, assignedVlan, portBuilder.build(), nextObj.id()).addToExisting();
if (!srManager.deviceConfiguration().isConfigured(deviceId)) {
log.debug("skip next flowobjective update for device: {}", deviceId);
} else {
// no need to update the flow here since we have updated the nextobjective/group
// the existing flow will keep pointing to the updated nextobj
srManager.flowObjectiveService.next(deviceId, newNextObj);
}
}
}
Aggregations