use of org.onlab.packet.MacAddress in project trellis-control by opennetworkinglab.
the class PolicyGroupHandler method createPolicyGroupChain.
/**
* Creates policy group chain.
*
* @param id unique identifier associated with the policy group
* @param params a list of policy group params
* @return policy group identifier
*/
public PolicyGroupIdentifier createPolicyGroupChain(String id, List<PolicyGroupParams> params) {
List<GroupBucketIdentifier> bucketIds = new ArrayList<>();
for (PolicyGroupParams param : params) {
List<PortNumber> ports = param.getPorts();
if (ports == null) {
log.warn("createPolicyGroupChain in sw {} with wrong " + "input parameters", deviceId);
return null;
}
int labelStackSize = (param.getLabelStack() != null) ? param.getLabelStack().size() : 0;
if (labelStackSize > 1) {
for (PortNumber sp : ports) {
PolicyGroupIdentifier previousGroupkey = null;
DeviceId neighbor = portDeviceMap.get(sp);
for (int idx = 0; idx < param.getLabelStack().size(); idx++) {
int label = param.getLabelStack().get(idx);
if (idx == (labelStackSize - 1)) {
// Innermost Group
GroupBucketIdentifier bucketId = new GroupBucketIdentifier(label, previousGroupkey);
bucketIds.add(bucketId);
} else if (idx == 0) {
// Outermost Group
List<GroupBucket> outBuckets = new ArrayList<>();
GroupBucketIdentifier bucketId = new GroupBucketIdentifier(label, sp);
PolicyGroupIdentifier key = new PolicyGroupIdentifier(id, Collections.singletonList(param), Collections.singletonList(bucketId));
MacAddress neighborEthDst;
try {
neighborEthDst = deviceConfig.getDeviceMac(neighbor);
} catch (DeviceConfigNotFoundException e) {
log.warn(e.getMessage() + " Skipping createPolicyGroupChain for this label.");
continue;
}
TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
tBuilder.setOutput(sp).setEthDst(neighborEthDst).setEthSrc(nodeMacAddr).pushMpls().setMpls(MplsLabel.mplsLabel(label));
/*outBuckets.add(DefaultGroupBucket.
createSelectGroupBucket(tBuilder.build()));
GroupDescription desc = new
DefaultGroupDescription(deviceId,
GroupDescription.Type.INDIRECT,
new GroupBuckets(outBuckets));
//TODO: BoS*/
previousGroupkey = key;
// groupService.addGroup(desc);
// TODO: Use nextObjective APIs here
} else {
// Intermediate Groups
GroupBucketIdentifier bucketId = new GroupBucketIdentifier(label, previousGroupkey);
PolicyGroupIdentifier key = new PolicyGroupIdentifier(id, Collections.singletonList(param), Collections.singletonList(bucketId));
// Add to group dependency list
dependentGroups.put(previousGroupkey, key);
previousGroupkey = key;
}
}
}
} else {
int label = -1;
if (labelStackSize == 1) {
label = param.getLabelStack().get(0);
}
for (PortNumber sp : ports) {
GroupBucketIdentifier bucketId = new GroupBucketIdentifier(label, sp);
bucketIds.add(bucketId);
}
}
}
PolicyGroupIdentifier innermostGroupkey = null;
if (!bucketIds.isEmpty()) {
innermostGroupkey = new PolicyGroupIdentifier(id, params, bucketIds);
// Add to group dependency list
boolean fullyResolved = true;
for (GroupBucketIdentifier bucketId : bucketIds) {
if (bucketId.type() == BucketOutputType.GROUP) {
dependentGroups.put(bucketId.outGroup(), innermostGroupkey);
fullyResolved = false;
}
}
if (fullyResolved) {
List<GroupBucket> outBuckets = new ArrayList<>();
for (GroupBucketIdentifier bucketId : bucketIds) {
DeviceId neighbor = portDeviceMap.get(bucketId.outPort());
MacAddress neighborEthDst;
try {
neighborEthDst = deviceConfig.getDeviceMac(neighbor);
} catch (DeviceConfigNotFoundException e) {
log.warn(e.getMessage() + " Skipping createPolicyGroupChain for this bucketId.");
continue;
}
TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
tBuilder.setOutput(bucketId.outPort()).setEthDst(neighborEthDst).setEthSrc(nodeMacAddr);
if (bucketId.label() != DestinationSet.NO_EDGE_LABEL) {
tBuilder.pushMpls().setMpls(MplsLabel.mplsLabel(bucketId.label()));
}
// TODO: BoS
/*outBuckets.add(DefaultGroupBucket.
createSelectGroupBucket(tBuilder.build()));*/
}
/*GroupDescription desc = new
DefaultGroupDescription(deviceId,
GroupDescription.Type.SELECT,
new GroupBuckets(outBuckets));
groupService.addGroup(desc);*/
// TODO: Use nextObjective APIs here
}
}
return innermostGroupkey;
}
use of org.onlab.packet.MacAddress in project trellis-control by opennetworkinglab.
the class RouteHandler method processRouteRemovedInternal.
private void processRouteRemovedInternal(Collection<ResolvedRoute> routes) {
if (!isReady()) {
log.info("System is not ready. Skip removing route for {}", routes);
return;
}
log.info("processRouteRemovedInternal. routes={}", routes);
Set<IpPrefix> allPrefixes = Sets.newHashSet();
routes.forEach(route -> {
allPrefixes.add(route.prefix());
});
log.debug("RouteRemoved. revokeSubnet {}", allPrefixes);
// FIXME remove routes more precisely by memorizing the old locations
srManager.defaultRoutingHandler.revokeSubnet(allPrefixes, null);
routes.forEach(route -> {
IpPrefix prefix = route.prefix();
MacAddress nextHopMac = route.nextHopMac();
VlanId nextHopVlan = route.nextHopVlan();
Set<ConnectPoint> locations = srManager.nextHopLocations(route);
locations.forEach(location -> {
log.debug("RouteRemoved. removeSubnet {}, {}", location, prefix);
srManager.deviceConfiguration.removeSubnet(location, prefix);
// We don't need to call revokeRoute again since revokeSubnet will remove the prefix
// from all devices, including the ones that next hop attaches to.
// revokeSubnet will also remove flow on the pair device (if exist) pointing to current location.
});
});
}
use of org.onlab.packet.MacAddress in project trellis-control by opennetworkinglab.
the class RouteHandler method processHostMovedEvent.
void processHostMovedEvent(HostEvent event) {
log.info("processHostMovedEvent {}", event);
MacAddress hostMac = event.subject().mac();
VlanId hostVlanId = event.subject().vlan();
Set<ConnectPoint> prevLocations = event.prevSubject().locations().stream().map(h -> (ConnectPoint) h).collect(Collectors.toSet());
Set<ConnectPoint> newLocations = event.subject().locations().stream().map(h -> (ConnectPoint) h).collect(Collectors.toSet());
List<Set<IpPrefix>> batchedSubnets = srManager.deviceConfiguration.getBatchedSubnets(event.subject().id());
Set<DeviceId> newDeviceIds = newLocations.stream().map(ConnectPoint::deviceId).collect(Collectors.toSet());
// Set of deviceIDs of the previous locations where the host was connected
// Used to determine if host moved to different connect points
// on same device or moved to a different device altogether
Set<DeviceId> oldDeviceIds = prevLocations.stream().map(ConnectPoint::deviceId).collect(Collectors.toSet());
// and only when the no. of routes with the host as next-hop is not zero
if (!batchedSubnets.isEmpty()) {
// For each new location, if NextObj exists for the host, update with new location ..
Sets.difference(newLocations, prevLocations).forEach(newLocation -> {
// NOTE: that we use the nexthop vlanId to retrieve the nextId
// while the vlanId used to program the L3 unicast chain
// is derived from the port configuration. In case of
// a tagged interface we use host vlanId. Host vlan should
// be part of the tags configured for that port. See the
// code in DefaultGroupHandler.updateL3UcastGroupBucket
int nextId = srManager.getMacVlanNextObjectiveId(newLocation.deviceId(), hostMac, hostVlanId, null, false);
if (nextId != -1) {
// Update the nextId group bucket
log.debug("HostMoved. NextId exists, update L3 Ucast Group Bucket {}, {}, {} --> {}", newLocation, hostMac, hostVlanId, nextId);
srManager.updateMacVlanTreatment(newLocation.deviceId(), hostMac, hostVlanId, newLocation.port(), nextId);
} else {
log.debug("HostMoved. NextId does not exist for this location {}, host {}/{}", newLocation, hostMac, hostVlanId);
}
});
}
batchedSubnets.forEach(subnets -> {
log.debug("HostMoved. populateSubnet {}, {}", newLocations, subnets);
srManager.defaultRoutingHandler.populateSubnet(newLocations, subnets);
subnets.forEach(prefix -> {
// For each old location
Sets.difference(prevLocations, newLocations).forEach(prevLocation -> {
// Otherwise, do not remove and let the adding part update the old flow
if (newDeviceIds.contains(prevLocation.deviceId())) {
return;
}
log.debug("HostMoved. removeSubnet {}, {}", prevLocation, prefix);
srManager.deviceConfiguration.removeSubnet(prevLocation, prefix);
// Do not remove flow from a device if the route is still reachable via its pair device.
// If spine exists,
// populateSubnet above will update the flow to point to its pair device via spine.
// If spine does not exist,
// processSingleLeafPair below will update the flow to point to its pair device via pair port.
DeviceId pairDeviceId = srManager.getPairDeviceId(prevLocation.deviceId()).orElse(null);
if (newLocations.stream().anyMatch(n -> n.deviceId().equals(pairDeviceId))) {
return;
}
log.debug("HostMoved. revokeRoute {}, {}, {}, {}", prevLocation, prefix, hostMac, hostVlanId);
srManager.defaultRoutingHandler.revokeRoute(prevLocation.deviceId(), prefix, hostMac, hostVlanId, prevLocation.port(), false);
});
// For each new location, add all new IPs.
Sets.difference(newLocations, prevLocations).forEach(newLocation -> {
log.debug("HostMoved. addSubnet {}, {}", newLocation, prefix);
srManager.deviceConfiguration.addSubnet(newLocation, prefix);
// its a new connect point, not a move from an existing device, populateRoute
if (!oldDeviceIds.contains(newLocation.deviceId())) {
log.debug("HostMoved. populateRoute {}, {}, {}, {}", newLocation, prefix, hostMac, hostVlanId);
srManager.defaultRoutingHandler.populateRoute(newLocation.deviceId(), prefix, hostMac, hostVlanId, newLocation.port(), false);
}
});
newLocations.forEach(location -> {
processSingleLeafPairIfNeeded(newLocations, location, prefix, hostVlanId);
});
});
});
}
use of org.onlab.packet.MacAddress in project trellis-control by opennetworkinglab.
the class RouteHandler method processSingleLeafPairIfNeeded.
protected boolean processSingleLeafPairIfNeeded(Set<ConnectPoint> locations, ConnectPoint location, IpPrefix prefix, VlanId nextHopVlan) {
// Special handling for single leaf pair
if (!srManager.getInfraDeviceIds().isEmpty()) {
log.debug("Spine found. Skip single leaf pair handling");
return false;
}
Optional<DeviceId> pairDeviceId = srManager.getPairDeviceId(location.deviceId());
if (pairDeviceId.isEmpty()) {
log.debug("Pair device of {} not found", location.deviceId());
return false;
}
if (locations.stream().anyMatch(l -> l.deviceId().equals(pairDeviceId.get()))) {
log.debug("Pair device has a next hop available. Leave it as is.");
return false;
}
Optional<PortNumber> pairRemotePort = srManager.getPairLocalPort(pairDeviceId.get());
if (pairRemotePort.isEmpty()) {
log.debug("Pair remote port of {} not found", pairDeviceId.get());
return false;
}
// Use routerMac of the pair device as the next hop
MacAddress effectiveMac;
try {
effectiveMac = srManager.getDeviceMacAddress(location.deviceId());
} catch (DeviceConfigNotFoundException e) {
log.warn("Abort populateRoute on pair device {}. routerMac not found", pairDeviceId);
return false;
}
// Since the pairLocalPort is trunk port, use assigned vlan of original port
// when the host is untagged
VlanId effectiveVlan = Optional.ofNullable(srManager.getInternalVlanId(location)).orElse(nextHopVlan);
log.debug("Single leaf pair. populateRoute {}/{}, {}, {}, {}", pairDeviceId, pairRemotePort, prefix, effectiveMac, effectiveVlan);
srManager.defaultRoutingHandler.populateRoute(pairDeviceId.get(), prefix, effectiveMac, effectiveVlan, pairRemotePort.get(), false);
return true;
}
use of org.onlab.packet.MacAddress in project trellis-control by opennetworkinglab.
the class RouteHandler method processRouteAddedInternal.
/**
* Internal logic that handles route addition.
*
* @param routes collection of routes to be processed
* @param populateRouteOnly true if we only want to populateRoute but not populateSubnet.
* Set it to true when initializing a device coming up.
* populateSubnet will be done when link comes up later so it is redundant.
* populateRoute still needs to be done for statically configured next hop hosts.
*/
private void processRouteAddedInternal(Collection<ResolvedRoute> routes, boolean populateRouteOnly) {
if (!isReady()) {
log.info("System is not ready. Skip adding route for {}", routes);
return;
}
log.info("processRouteAddedInternal. routes={}", routes);
if (routes.size() > 2) {
log.info("Route {} has more than two next hops. Do not process route change", routes);
return;
}
if (routes.isEmpty()) {
log.warn("No resolved route found. Abort processRouteAddedInternal");
return;
}
Set<ConnectPoint> allLocations = Sets.newHashSet();
Set<IpPrefix> allPrefixes = Sets.newHashSet();
routes.forEach(route -> {
allLocations.addAll(srManager.nextHopLocations(route));
allPrefixes.add(route.prefix());
});
log.debug("RouteAdded. populateSubnet {}, {}", allLocations, allPrefixes);
srManager.defaultRoutingHandler.populateSubnet(allLocations, allPrefixes);
routes.forEach(route -> {
IpPrefix prefix = route.prefix();
MacAddress nextHopMac = route.nextHopMac();
VlanId nextHopVlan = route.nextHopVlan();
Set<ConnectPoint> locations = srManager.nextHopLocations(route);
locations.forEach(location -> {
log.debug("RouteAdded. addSubnet {}, {}", location, prefix);
srManager.deviceConfiguration.addSubnet(location, prefix);
log.debug("RouteAdded populateRoute {}, {}, {}, {}", location, prefix, nextHopMac, nextHopVlan);
srManager.defaultRoutingHandler.populateRoute(location.deviceId(), prefix, nextHopMac, nextHopVlan, location.port(), false);
processSingleLeafPairIfNeeded(locations, location, prefix, nextHopVlan);
});
});
}
Aggregations