mirror of
https://github.com/opennetworkinglab/onos.git
synced 2026-02-11 18:51:35 +01:00
Route reprogamming using group substitution during next hop movement
Change-Id: Idf8362dac522722ca67747e245bfd836e6ee6292
This commit is contained in:
parent
a3ce00ba00
commit
ef0761c211
@ -1118,11 +1118,12 @@ public class DefaultRoutingHandler {
|
||||
* @param hostMac MAC address of the next hop
|
||||
* @param hostVlanId Vlan ID of the nexthop
|
||||
* @param outPort port where the next hop attaches to
|
||||
* @param directHost host is of type direct or indirect
|
||||
*/
|
||||
void populateRoute(DeviceId deviceId, IpPrefix prefix,
|
||||
MacAddress hostMac, VlanId hostVlanId, PortNumber outPort) {
|
||||
MacAddress hostMac, VlanId hostVlanId, PortNumber outPort, boolean directHost) {
|
||||
if (shouldProgram(deviceId)) {
|
||||
srManager.routingRulePopulator.populateRoute(deviceId, prefix, hostMac, hostVlanId, outPort);
|
||||
srManager.routingRulePopulator.populateRoute(deviceId, prefix, hostMac, hostVlanId, outPort, directHost);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1135,11 +1136,12 @@ public class DefaultRoutingHandler {
|
||||
* @param hostMac MAC address of the next hop
|
||||
* @param hostVlanId Vlan ID of the nexthop
|
||||
* @param outPort port that next hop attaches to
|
||||
* @param directHost host is of type direct or indirect
|
||||
*/
|
||||
void revokeRoute(DeviceId deviceId, IpPrefix prefix,
|
||||
MacAddress hostMac, VlanId hostVlanId, PortNumber outPort) {
|
||||
MacAddress hostMac, VlanId hostVlanId, PortNumber outPort, boolean directHost) {
|
||||
if (shouldProgram(deviceId)) {
|
||||
srManager.routingRulePopulator.revokeRoute(deviceId, prefix, hostMac, hostVlanId, outPort);
|
||||
srManager.routingRulePopulator.revokeRoute(deviceId, prefix, hostMac, hostVlanId, outPort, directHost);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -525,9 +525,9 @@ public class HostHandler {
|
||||
|
||||
log.info("{} routing rule for {} at {}", revoke ? "Revoking" : "Populating", ip, location);
|
||||
if (revoke) {
|
||||
srManager.defaultRoutingHandler.revokeRoute(deviceId, ip.toIpPrefix(), mac, vlanId, port);
|
||||
srManager.defaultRoutingHandler.revokeRoute(deviceId, ip.toIpPrefix(), mac, vlanId, port, true);
|
||||
} else {
|
||||
srManager.defaultRoutingHandler.populateRoute(deviceId, ip.toIpPrefix(), mac, vlanId, port);
|
||||
srManager.defaultRoutingHandler.populateRoute(deviceId, ip.toIpPrefix(), mac, vlanId, port, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -675,10 +675,10 @@ public class HostHandler {
|
||||
ipPrefixSet.forEach(ipPrefix -> {
|
||||
if (install && ipPrefix.contains(hostIpAddress)) {
|
||||
srManager.defaultRoutingHandler.populateRoute(cp.deviceId(), hostIpAddress.toIpPrefix(),
|
||||
host.mac(), host.vlan(), cp.port());
|
||||
host.mac(), host.vlan(), cp.port(), true);
|
||||
} else if (!install && ipPrefix.contains(hostIpAddress)) {
|
||||
srManager.defaultRoutingHandler.revokeRoute(cp.deviceId(), hostIpAddress.toIpPrefix(),
|
||||
host.mac(), host.vlan(), cp.port());
|
||||
host.mac(), host.vlan(), cp.port(), true);
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
@ -32,6 +32,8 @@ import org.onosproject.routeservice.RouteInfo;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
@ -101,7 +103,7 @@ public class RouteHandler {
|
||||
srManager.deviceConfiguration.addSubnet(location, prefix);
|
||||
log.debug("RouteAdded populateRoute {}, {}, {}, {}", location, prefix, nextHopMac, nextHopVlan);
|
||||
srManager.defaultRoutingHandler.populateRoute(location.deviceId(), prefix,
|
||||
nextHopMac, nextHopVlan, location.port());
|
||||
nextHopMac, nextHopVlan, location.port(), false);
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -175,7 +177,7 @@ public class RouteHandler {
|
||||
srManager.deviceConfiguration.addSubnet(location, prefix);
|
||||
log.debug("RouteUpdated. populateRoute {}, {}, {}, {}", location, prefix, nextHopMac, nextHopVlan);
|
||||
srManager.defaultRoutingHandler.populateRoute(location.deviceId(), prefix,
|
||||
nextHopMac, nextHopVlan, location.port());
|
||||
nextHopMac, nextHopVlan, location.port(), false);
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -221,7 +223,7 @@ public class RouteHandler {
|
||||
|
||||
log.debug("RouteRemoved. revokeRoute {}, {}, {}, {}", location, prefix, nextHopMac, nextHopVlan);
|
||||
srManager.defaultRoutingHandler.revokeRoute(pairDeviceId.get(), prefix,
|
||||
nextHopMac, vlanId, pairLocalPort.get());
|
||||
nextHopMac, vlanId, pairLocalPort.get(), false);
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -231,6 +233,8 @@ public class RouteHandler {
|
||||
log.info("processHostMovedEvent {}", event);
|
||||
MacAddress hostMac = event.subject().mac();
|
||||
VlanId hostVlanId = event.subject().vlan();
|
||||
// map of nextId for prev port in each device
|
||||
Map<DeviceId, Integer> nextIdMap = new HashMap<>();
|
||||
|
||||
affectedRoutes(hostMac, hostVlanId).forEach(affectedRoute -> {
|
||||
IpPrefix prefix = affectedRoute.prefix();
|
||||
@ -245,8 +249,22 @@ public class RouteHandler {
|
||||
Set<DeviceId> newDeviceIds = newLocations.stream().map(HostLocation::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(HostLocation::deviceId)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
// For each old location
|
||||
Sets.difference(prevLocations, newLocations).forEach(prevLocation -> {
|
||||
//find next Id for each old port, add to map
|
||||
int nextId = srManager.getNextIdForHostPort(prevLocation.deviceId(), hostMac,
|
||||
hostVlanId, prevLocation.port());
|
||||
log.debug("HostMoved. NextId For Host {}, {}, {}, {} {}", prevLocation, prefix,
|
||||
hostMac, hostVlanId, nextId);
|
||||
|
||||
nextIdMap.put(prevLocation.deviceId(), nextId);
|
||||
|
||||
// Remove flows for unchanged IPs only when the host moves from a switch to another.
|
||||
// Otherwise, do not remove and let the adding part update the old flow
|
||||
if (newDeviceIds.contains(prevLocation.deviceId())) {
|
||||
@ -265,7 +283,7 @@ public class RouteHandler {
|
||||
|
||||
log.debug("HostMoved. revokeRoute {}, {}, {}, {}", prevLocation, prefix, hostMac, hostVlanId);
|
||||
srManager.defaultRoutingHandler.revokeRoute(prevLocation.deviceId(), prefix,
|
||||
hostMac, hostVlanId, prevLocation.port());
|
||||
hostMac, hostVlanId, prevLocation.port(), false);
|
||||
});
|
||||
|
||||
// For each new location, add all new IPs.
|
||||
@ -273,9 +291,20 @@ public class RouteHandler {
|
||||
log.debug("HostMoved. addSubnet {}, {}", newLocation, prefix);
|
||||
srManager.deviceConfiguration.addSubnet(newLocation, prefix);
|
||||
|
||||
log.debug("HostMoved. populateRoute {}, {}, {}, {}", newLocation, prefix, hostMac, hostVlanId);
|
||||
srManager.defaultRoutingHandler.populateRoute(newLocation.deviceId(), prefix,
|
||||
hostMac, hostVlanId, newLocation.port());
|
||||
//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);
|
||||
} else {
|
||||
// update same flow to point to new nextObj
|
||||
VlanId vlanId = Optional.ofNullable(srManager.getInternalVlanId(newLocation)).orElse(hostVlanId);
|
||||
//use nextIdMap to send new port details to update the nextId group bucket
|
||||
log.debug("HostMoved. update L3 Ucast Group Bucket {}, {}, {} --> {}",
|
||||
newLocation, hostMac, vlanId, nextIdMap.get(newLocation.deviceId()));
|
||||
srManager.updateMacVlanTreatment(newLocation.deviceId(), hostMac, vlanId,
|
||||
newLocation.port(), nextIdMap.get(newLocation.deviceId()));
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@ -303,15 +303,16 @@ public class RoutingRulePopulator {
|
||||
* @param hostMac MAC address of the next hop
|
||||
* @param hostVlanId Vlan ID of the nexthop
|
||||
* @param outPort port where the next hop attaches to
|
||||
* @param directHost host is of type direct or indirect
|
||||
*/
|
||||
void populateRoute(DeviceId deviceId, IpPrefix prefix,
|
||||
MacAddress hostMac, VlanId hostVlanId, PortNumber outPort) {
|
||||
MacAddress hostMac, VlanId hostVlanId, PortNumber outPort, boolean directHost) {
|
||||
log.debug("Populate direct routing entry for route {} at {}:{}",
|
||||
prefix, deviceId, outPort);
|
||||
ForwardingObjective.Builder fwdBuilder;
|
||||
try {
|
||||
fwdBuilder = routingFwdObjBuilder(deviceId, prefix, hostMac,
|
||||
hostVlanId, outPort, false);
|
||||
hostVlanId, outPort, directHost, false);
|
||||
} catch (DeviceConfigNotFoundException e) {
|
||||
log.warn(e.getMessage() + " Aborting direct populateRoute");
|
||||
return;
|
||||
@ -342,15 +343,16 @@ public class RoutingRulePopulator {
|
||||
* @param hostMac MAC address of the next hop
|
||||
* @param hostVlanId Vlan ID of the nexthop
|
||||
* @param outPort port that next hop attaches to
|
||||
* @param directHost host is of type direct or indirect
|
||||
*/
|
||||
void revokeRoute(DeviceId deviceId, IpPrefix prefix,
|
||||
MacAddress hostMac, VlanId hostVlanId, PortNumber outPort) {
|
||||
MacAddress hostMac, VlanId hostVlanId, PortNumber outPort, boolean directHost) {
|
||||
log.debug("Revoke IP table entry for route {} at {}:{}",
|
||||
prefix, deviceId, outPort);
|
||||
ForwardingObjective.Builder fwdBuilder;
|
||||
try {
|
||||
fwdBuilder = routingFwdObjBuilder(deviceId, prefix, hostMac,
|
||||
hostVlanId, outPort, true);
|
||||
hostVlanId, outPort, directHost, true);
|
||||
} catch (DeviceConfigNotFoundException e) {
|
||||
log.warn(e.getMessage() + " Aborting revokeIpRuleForHost.");
|
||||
return;
|
||||
@ -379,16 +381,22 @@ public class RoutingRulePopulator {
|
||||
* @param hostVlanId Vlan ID of the nexthop
|
||||
* @param outPort port where the nexthop attaches to
|
||||
* @param revoke true if forwarding objective is meant to revoke forwarding rule
|
||||
* @param directHost host is direct or indirect
|
||||
* @return forwarding objective builder
|
||||
* @throws DeviceConfigNotFoundException if given device is not configured
|
||||
*/
|
||||
private ForwardingObjective.Builder routingFwdObjBuilder(
|
||||
|
||||
private ForwardingObjective.Builder
|
||||
|
||||
|
||||
routingFwdObjBuilder(
|
||||
DeviceId deviceId, IpPrefix prefix,
|
||||
MacAddress hostMac, VlanId hostVlanId, PortNumber outPort,
|
||||
boolean revoke)
|
||||
boolean directHost, boolean revoke)
|
||||
throws DeviceConfigNotFoundException {
|
||||
MacAddress deviceMac;
|
||||
deviceMac = config.getDeviceMac(deviceId);
|
||||
int nextObjId = -1;
|
||||
|
||||
ConnectPoint connectPoint = new ConnectPoint(deviceId, outPort);
|
||||
VlanId untaggedVlan = srManager.interfaceService.getUntaggedVlanId(connectPoint);
|
||||
@ -435,18 +443,26 @@ public class RoutingRulePopulator {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// if the objective is to revoke an existing rule, and for some reason
|
||||
// the next-objective does not exist, then a new one should not be created
|
||||
int portNextObjId = srManager.getPortNextObjectiveId(deviceId, outPort,
|
||||
|
||||
if (directHost) {
|
||||
// if the objective is to revoke an existing rule, and for some reason
|
||||
// the next-objective does not exist, then a new one should not be created
|
||||
nextObjId = srManager.getPortNextObjectiveId(deviceId, outPort,
|
||||
tbuilder.build(), mbuilder.build(), !revoke);
|
||||
if (portNextObjId == -1) {
|
||||
// Warning log will come from getPortNextObjective method
|
||||
} else {
|
||||
// if the objective is to revoke an existing rule, and for some reason
|
||||
// the next-objective does not exist, then a new one should not be created
|
||||
nextObjId = srManager.getMacVlanNextObjectiveId(deviceId, hostMac, hostVlanId,
|
||||
tbuilder.build(), mbuilder.build(), !revoke);
|
||||
}
|
||||
if (nextObjId == -1) {
|
||||
// Warning log will come from getMacVlanNextObjective method
|
||||
return null;
|
||||
}
|
||||
|
||||
return DefaultForwardingObjective.builder()
|
||||
.withSelector(sbuilder.build())
|
||||
.nextStep(portNextObjId)
|
||||
.nextStep(nextObjId)
|
||||
.fromApp(srManager.appId).makePermanent()
|
||||
.withPriority(getPriorityFromPrefix(prefix))
|
||||
.withFlag(ForwardingObjective.Flag.SPECIFIC);
|
||||
@ -1711,7 +1727,7 @@ public class RoutingRulePopulator {
|
||||
));
|
||||
});
|
||||
try {
|
||||
fwdBuilder = routingFwdObjBuilder(deviceId, prefix, hostMac, dummyVlan, outPort, false);
|
||||
fwdBuilder = routingFwdObjBuilder(deviceId, prefix, hostMac, dummyVlan, outPort, false, false);
|
||||
} catch (DeviceConfigNotFoundException e) {
|
||||
log.error(e.getMessage() + " Aborting populateDoubleTaggedRoute");
|
||||
return;
|
||||
@ -1750,7 +1766,7 @@ public class RoutingRulePopulator {
|
||||
void revokeDoubleTaggedRoute(DeviceId deviceId, IpPrefix prefix, MacAddress hostMac,
|
||||
VlanId hostVlan, VlanId innerVlan, VlanId outerVlan,
|
||||
EthType outerTpid, PortNumber outPort) {
|
||||
revokeRoute(deviceId, prefix, hostMac, hostVlan, outPort);
|
||||
revokeRoute(deviceId, prefix, hostMac, hostVlan, outPort, false);
|
||||
|
||||
DummyVlanIdStoreKey key = new DummyVlanIdStoreKey(
|
||||
new ConnectPoint(deviceId, outPort), prefix.address());
|
||||
|
||||
@ -27,6 +27,7 @@ import org.onlab.packet.IPv6;
|
||||
import org.onlab.packet.IpAddress;
|
||||
import org.onlab.packet.IpPrefix;
|
||||
import org.onlab.packet.VlanId;
|
||||
import org.onlab.packet.MacAddress;
|
||||
import org.onlab.util.KryoNamespace;
|
||||
import org.onlab.util.Tools;
|
||||
import org.onosproject.cfg.ComponentConfigService;
|
||||
@ -115,6 +116,7 @@ import org.onosproject.segmentrouting.storekey.DestinationSetNextObjectiveStoreK
|
||||
import org.onosproject.segmentrouting.storekey.DummyVlanIdStoreKey;
|
||||
import org.onosproject.segmentrouting.storekey.PortNextObjectiveStoreKey;
|
||||
import org.onosproject.segmentrouting.storekey.VlanNextObjectiveStoreKey;
|
||||
import org.onosproject.segmentrouting.storekey.MacVlanNextObjectiveStoreKey;
|
||||
import org.onosproject.segmentrouting.storekey.XConnectStoreKey;
|
||||
import org.onosproject.segmentrouting.xconnect.api.XconnectService;
|
||||
import org.onosproject.store.serializers.KryoNamespaces;
|
||||
@ -346,7 +348,7 @@ public class SegmentRoutingManager implements SegmentRoutingService {
|
||||
vlanNextObjStore = null;
|
||||
/**
|
||||
* Per device next objective ID store with (device id + port + treatment + meta) as key.
|
||||
* Used to keep track on L2 interface group and L3 unicast group information.
|
||||
* Used to keep track on L2 interface group and L3 unicast group information for direct hosts.
|
||||
*/
|
||||
private EventuallyConsistentMap<PortNextObjectiveStoreKey, Integer>
|
||||
portNextObjStore = null;
|
||||
@ -358,6 +360,13 @@ public class SegmentRoutingManager implements SegmentRoutingService {
|
||||
private EventuallyConsistentMap<DummyVlanIdStoreKey, VlanId>
|
||||
dummyVlanIdStore = null;
|
||||
|
||||
/**
|
||||
* Per device next objective ID store with (device id + MAC address + vlan) as key.
|
||||
* Used to keep track of L3 unicast group for indirect hosts.
|
||||
*/
|
||||
private EventuallyConsistentMap<MacVlanNextObjectiveStoreKey, Integer>
|
||||
macVlanNextObjStore = null;
|
||||
|
||||
private EventuallyConsistentMap<String, Tunnel> tunnelStore = null;
|
||||
private EventuallyConsistentMap<String, Policy> policyStore = null;
|
||||
|
||||
@ -471,6 +480,15 @@ public class SegmentRoutingManager implements SegmentRoutingService {
|
||||
.withTimestampProvider((k, v) -> new WallClockTimestamp())
|
||||
.build();
|
||||
|
||||
log.debug("Creating EC map macvlannextobjectivestore");
|
||||
EventuallyConsistentMapBuilder<MacVlanNextObjectiveStoreKey, Integer>
|
||||
macVlanNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
|
||||
macVlanNextObjStore = macVlanNextObjMapBuilder
|
||||
.withName("macvlannextobjectivestore")
|
||||
.withSerializer(createSerializer())
|
||||
.withTimestampProvider((k, v) -> new WallClockTimestamp())
|
||||
.build();
|
||||
|
||||
log.debug("Creating EC map subnetnextobjectivestore");
|
||||
EventuallyConsistentMapBuilder<PortNextObjectiveStoreKey, Integer>
|
||||
portNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
|
||||
@ -602,7 +620,8 @@ public class SegmentRoutingManager implements SegmentRoutingService {
|
||||
L2TunnelPolicy.class,
|
||||
DefaultL2Tunnel.class,
|
||||
DefaultL2TunnelPolicy.class,
|
||||
DummyVlanIdStoreKey.class
|
||||
DummyVlanIdStoreKey.class,
|
||||
MacVlanNextObjectiveStoreKey.class
|
||||
);
|
||||
}
|
||||
|
||||
@ -650,6 +669,7 @@ public class SegmentRoutingManager implements SegmentRoutingService {
|
||||
|
||||
dsNextObjStore.destroy();
|
||||
vlanNextObjStore.destroy();
|
||||
macVlanNextObjStore.destroy();
|
||||
portNextObjStore.destroy();
|
||||
dummyVlanIdStore.destroy();
|
||||
tunnelStore.destroy();
|
||||
@ -946,6 +966,15 @@ public class SegmentRoutingManager implements SegmentRoutingService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableMap<MacVlanNextObjectiveStoreKey, Integer> getMacVlanNextObjStore() {
|
||||
if (macVlanNextObjStore != null) {
|
||||
return ImmutableMap.copyOf(macVlanNextObjStore.entrySet());
|
||||
} else {
|
||||
return ImmutableMap.of();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableMap<PortNextObjectiveStoreKey, Integer> getPortNextObjStore() {
|
||||
if (portNextObjStore != null) {
|
||||
@ -989,6 +1018,13 @@ public class SegmentRoutingManager implements SegmentRoutingService {
|
||||
}
|
||||
});
|
||||
}
|
||||
if (macVlanNextObjStore != null) {
|
||||
macVlanNextObjStore.entrySet().forEach(e -> {
|
||||
if (e.getValue() == nextId) {
|
||||
macVlanNextObjStore.remove(e.getKey());
|
||||
}
|
||||
});
|
||||
}
|
||||
if (portNextObjStore != null) {
|
||||
portNextObjStore.entrySet().forEach(e -> {
|
||||
if (e.getValue() == nextId) {
|
||||
@ -1108,9 +1144,19 @@ public class SegmentRoutingManager implements SegmentRoutingService {
|
||||
return vlanNextObjStore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Per device next objective ID store with (device id + MAC address + vlan) as key.
|
||||
* Used to keep track on L3 Unicast group information for indirect hosts.
|
||||
*
|
||||
* @return mac vlan next object store
|
||||
*/
|
||||
public EventuallyConsistentMap<MacVlanNextObjectiveStoreKey, Integer> macVlanNextObjStore() {
|
||||
return macVlanNextObjStore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Per device next objective ID store with (device id + port + treatment + meta) as key.
|
||||
* Used to keep track on L2 interface group and L3 unicast group information.
|
||||
* Used to keep track on L2 interface group and L3 unicast group information for direct hosts.
|
||||
*
|
||||
* @return port next object store.
|
||||
*/
|
||||
@ -1253,6 +1299,76 @@ public class SegmentRoutingManager implements SegmentRoutingService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next Objective ID for the given mac and vlan, given the treatment.
|
||||
* There could be multiple different treatments to the same outport, which
|
||||
* would result in different objectives. If the next object does not exist,
|
||||
* and should be created, a new one is created and its id is returned.
|
||||
*
|
||||
* @param deviceId Device ID
|
||||
* @param macAddr mac of host for which Next ID is required.
|
||||
* @param vlanId vlan of host for which Next ID is required.
|
||||
* @param treatment the actions to apply on the packets (should include outport)
|
||||
* @param meta metadata passed into the creation of a Next Objective if necessary
|
||||
* @param createIfMissing true if a next object should be created if not found
|
||||
* @return next objective ID or -1 if an error occurred during retrieval or creation
|
||||
*/
|
||||
public int getMacVlanNextObjectiveId(DeviceId deviceId, MacAddress macAddr, VlanId vlanId,
|
||||
TrafficTreatment treatment,
|
||||
TrafficSelector meta,
|
||||
boolean createIfMissing) {
|
||||
DefaultGroupHandler ghdlr = groupHandlerMap.get(deviceId);
|
||||
if (ghdlr != null) {
|
||||
return ghdlr.getMacVlanNextObjectiveId(macAddr, vlanId, treatment, meta, createIfMissing);
|
||||
} else {
|
||||
log.warn("getMacVlanNextObjectiveId query - groupHandler for device {}"
|
||||
+ " not found", deviceId);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next ID for the given host port from the store.
|
||||
*
|
||||
* @param deviceId Device ID
|
||||
* @param hostMac mac of host for which Next ID is required.
|
||||
* @param hostVlanId vlan of host for which Next ID is required.
|
||||
* @param port port of device for which next ID is required.
|
||||
* @return next objective ID or -1 if an error occurred during retrieval
|
||||
*/
|
||||
public int getNextIdForHostPort(DeviceId deviceId, MacAddress hostMac,
|
||||
VlanId hostVlanId, PortNumber port) {
|
||||
DefaultGroupHandler ghdlr = groupHandlerMap.get(deviceId);
|
||||
if (ghdlr != null) {
|
||||
return ghdlr.getNextIdForHostPort(hostMac, hostVlanId, port);
|
||||
} else {
|
||||
log.warn("getNextIdForHostPort query - groupHandler for device {}"
|
||||
+ " not found", deviceId);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the next objective for the given nextId .
|
||||
*
|
||||
* @param deviceId Device ID
|
||||
* @param hostMac mac of host for which Next obj is to be updated.
|
||||
* @param hostVlanId vlan of host for which Next obj is to be updated.
|
||||
* @param port port with which to update the Next Obj.
|
||||
* @param nextId of Next Obj which needs to be updated.
|
||||
*/
|
||||
public void updateMacVlanTreatment(DeviceId deviceId, MacAddress hostMac,
|
||||
VlanId hostVlanId, PortNumber port, int nextId) {
|
||||
DefaultGroupHandler ghdlr = groupHandlerMap.get(deviceId);
|
||||
if (ghdlr != null) {
|
||||
ghdlr.updateL3UcastGroupBucket(hostMac, hostVlanId, port, nextId);
|
||||
} else {
|
||||
log.warn("updateL3UcastGroupBucket query - groupHandler for device {}"
|
||||
+ " not found", deviceId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the group handler object for the specified device id.
|
||||
*
|
||||
@ -1584,6 +1700,9 @@ public class SegmentRoutingManager implements SegmentRoutingService {
|
||||
vlanNextObjStore.entrySet().stream()
|
||||
.filter(entry -> entry.getKey().deviceId().equals(device.id()))
|
||||
.forEach(entry -> vlanNextObjStore.remove(entry.getKey()));
|
||||
macVlanNextObjStore.entrySet().stream()
|
||||
.filter(entry -> entry.getKey().deviceId().equals(device.id()))
|
||||
.forEach(entry -> macVlanNextObjStore.remove(entry.getKey()));
|
||||
portNextObjStore.entrySet().stream()
|
||||
.filter(entry -> entry.getKey().deviceId().equals(device.id()))
|
||||
.forEach(entry -> portNextObjStore.remove(entry.getKey()));
|
||||
|
||||
@ -42,6 +42,7 @@ import com.google.common.collect.ImmutableMap;
|
||||
import org.onosproject.segmentrouting.mcast.McastStoreKey;
|
||||
import org.onosproject.segmentrouting.storekey.PortNextObjectiveStoreKey;
|
||||
import org.onosproject.segmentrouting.storekey.VlanNextObjectiveStoreKey;
|
||||
import org.onosproject.segmentrouting.storekey.MacVlanNextObjectiveStoreKey;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -225,6 +226,13 @@ public interface SegmentRoutingService {
|
||||
*/
|
||||
ImmutableMap<VlanNextObjectiveStoreKey, Integer> getVlanNextObjStore();
|
||||
|
||||
/**
|
||||
* Returns the Mac Vlan next objective store.
|
||||
*
|
||||
* @return current contents of the macVlanNextObjStore
|
||||
*/
|
||||
ImmutableMap<MacVlanNextObjectiveStoreKey, Integer> getMacVlanNextObjStore();
|
||||
|
||||
/**
|
||||
* Returns the port next objective store.
|
||||
*
|
||||
|
||||
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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.segmentrouting.cli;
|
||||
|
||||
import org.apache.karaf.shell.api.action.Command;
|
||||
import org.apache.karaf.shell.api.action.lifecycle.Service;
|
||||
import org.onosproject.cli.AbstractShellCommand;
|
||||
import org.onosproject.segmentrouting.SegmentRoutingService;
|
||||
import org.onosproject.segmentrouting.storekey.MacVlanNextObjectiveStoreKey;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Command to read the current state of the macVlanNextObjStore.
|
||||
*/
|
||||
@Service
|
||||
@Command(scope = "onos", name = "sr-next-mac-vlan",
|
||||
description = "Displays the current next-hop / next-id it mapping")
|
||||
public class NextMacVlanCommand extends AbstractShellCommand {
|
||||
@Override
|
||||
protected void doExecute() {
|
||||
SegmentRoutingService srService =
|
||||
AbstractShellCommand.get(SegmentRoutingService.class);
|
||||
print(srService.getMacVlanNextObjStore());
|
||||
}
|
||||
|
||||
private void print(Map<MacVlanNextObjectiveStoreKey, Integer> macVlanNextObjStore) {
|
||||
ArrayList<MacVlanNextObjectiveStoreKey> a = new ArrayList<>(macVlanNextObjStore.keySet());
|
||||
a.sort(Comparator
|
||||
.comparing((MacVlanNextObjectiveStoreKey o) -> o.deviceId().toString())
|
||||
.thenComparing((MacVlanNextObjectiveStoreKey o) -> o.vlanId().toString())
|
||||
.thenComparing((MacVlanNextObjectiveStoreKey o) -> o.macAddr().toString()));
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
a.forEach(k ->
|
||||
builder.append("\n")
|
||||
.append(k)
|
||||
.append(" --> ")
|
||||
.append(macVlanNextObjStore.get(k))
|
||||
);
|
||||
print(builder.toString());
|
||||
}
|
||||
}
|
||||
@ -44,9 +44,11 @@ import org.onosproject.segmentrouting.DefaultRoutingHandler;
|
||||
import org.onosproject.segmentrouting.SegmentRoutingManager;
|
||||
import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
|
||||
import org.onosproject.segmentrouting.config.DeviceProperties;
|
||||
import org.onosproject.segmentrouting.config.DeviceConfiguration;
|
||||
import org.onosproject.segmentrouting.storekey.DestinationSetNextObjectiveStoreKey;
|
||||
import org.onosproject.segmentrouting.storekey.PortNextObjectiveStoreKey;
|
||||
import org.onosproject.segmentrouting.storekey.VlanNextObjectiveStoreKey;
|
||||
import org.onosproject.segmentrouting.storekey.MacVlanNextObjectiveStoreKey;
|
||||
import org.onosproject.store.service.EventuallyConsistentMap;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
@ -88,6 +90,8 @@ public class DefaultGroupHandler {
|
||||
protected MacAddress nodeMacAddr = null;
|
||||
protected LinkService linkService;
|
||||
protected FlowObjectiveService flowObjectiveService;
|
||||
private DeviceConfiguration config;
|
||||
|
||||
/**
|
||||
* local store for neighbor-device-ids and the set of ports on this device
|
||||
* that connect to the same neighbor.
|
||||
@ -106,6 +110,9 @@ public class DefaultGroupHandler {
|
||||
// distributed store for (device+subnet-ip-prefix) mapped to next-id
|
||||
protected EventuallyConsistentMap<VlanNextObjectiveStoreKey, Integer>
|
||||
vlanNextObjStore = null;
|
||||
// distributed store for (device+mac+vlan+treatment) mapped to next-id
|
||||
protected EventuallyConsistentMap<MacVlanNextObjectiveStoreKey, Integer>
|
||||
macVlanNextObjStore = null;
|
||||
// distributed store for (device+port+treatment) mapped to next-id
|
||||
protected EventuallyConsistentMap<PortNextObjectiveStoreKey, Integer>
|
||||
portNextObjStore = null;
|
||||
@ -145,6 +152,7 @@ public class DefaultGroupHandler {
|
||||
this.dsNextObjStore = srManager.dsNextObjStore();
|
||||
this.vlanNextObjStore = srManager.vlanNextObjStore();
|
||||
this.portNextObjStore = srManager.portNextObjStore();
|
||||
this.macVlanNextObjStore = srManager.macVlanNextObjStore();
|
||||
this.srManager = srManager;
|
||||
executorService.scheduleWithFixedDelay(new BucketCorrector(), 10,
|
||||
VERIFY_INTERVAL,
|
||||
@ -815,6 +823,52 @@ public class DefaultGroupHandler {
|
||||
return (nextId != null) ? nextId : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next objective of type simple associated with the mac/vlan on the
|
||||
* device, given the treatment. Different treatments to the same mac/vlan result
|
||||
* in different next objectives. If no such objective exists, this method
|
||||
* creates one (if requested) and returns the id. Optionally metadata can be passed in for
|
||||
* the creation of the objective. Typically this is used for L2 and L3 forwarding
|
||||
* to compute nodes and containers/VMs on the compute nodes directly attached
|
||||
* to the switch.
|
||||
*
|
||||
* @param macAddr the mac addr for the simple next objective
|
||||
* @param vlanId the vlan for the simple next objective
|
||||
* @param treatment the actions to apply on the packets (should include outport)
|
||||
* @param meta optional metadata passed into the creation of the next objective
|
||||
* @param createIfMissing true if a next object should be created if not found
|
||||
* @return int if found or created, -1 if there are errors during the
|
||||
* creation of the next objective.
|
||||
*/
|
||||
public int getMacVlanNextObjectiveId(MacAddress macAddr, VlanId vlanId, TrafficTreatment treatment,
|
||||
TrafficSelector meta, boolean createIfMissing) {
|
||||
|
||||
Integer nextId = macVlanNextObjStore
|
||||
.get(new MacVlanNextObjectiveStoreKey(deviceId, macAddr, vlanId));
|
||||
|
||||
if (nextId != null) {
|
||||
return nextId;
|
||||
}
|
||||
|
||||
log.debug("getMacVlanNextObjectiveId in device {}: Next objective id "
|
||||
+ "not found for host : {}/{} .. {}", deviceId, macAddr, vlanId,
|
||||
(createIfMissing) ? "creating" : "aborting");
|
||||
|
||||
if (!createIfMissing) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* create missing next objective */
|
||||
nextId = createGroupFromMacVlan(macAddr, vlanId, treatment, meta);
|
||||
if (nextId == null) {
|
||||
log.warn("getMacVlanNextObjectiveId: unable to create next obj"
|
||||
+ "for dev:{} host:{}/{}", deviceId, macAddr, vlanId);
|
||||
return -1;
|
||||
}
|
||||
return nextId;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the next objective of type simple associated with the port on the
|
||||
* device, given the treatment. Different treatments to the same port result
|
||||
@ -1176,6 +1230,45 @@ public class DefaultGroupHandler {
|
||||
.stream().noneMatch(intf -> intf.vlanTagged().contains(vlanId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create simple next objective for an indirect host mac/vlan. The treatments can include
|
||||
* all outgoing actions that need to happen on the packet.
|
||||
*
|
||||
* @param macAddr the mac address of the host
|
||||
* @param vlanId the vlan of the host
|
||||
* @param treatment the actions to apply on the packets (should include outport)
|
||||
* @param meta optional data to pass to the driver
|
||||
* @return next objective ID
|
||||
*/
|
||||
public int createGroupFromMacVlan(MacAddress macAddr, VlanId vlanId, TrafficTreatment treatment,
|
||||
TrafficSelector meta) {
|
||||
int nextId = flowObjectiveService.allocateNextId();
|
||||
MacVlanNextObjectiveStoreKey key = new MacVlanNextObjectiveStoreKey(deviceId, macAddr, vlanId);
|
||||
|
||||
NextObjective.Builder nextObjBuilder = DefaultNextObjective
|
||||
.builder().withId(nextId)
|
||||
.withType(NextObjective.Type.SIMPLE)
|
||||
.addTreatment(treatment)
|
||||
.fromApp(appId)
|
||||
.withMeta(meta);
|
||||
|
||||
ObjectiveContext context = new DefaultObjectiveContext(
|
||||
(objective) ->
|
||||
log.debug("createGroupFromMacVlan installed "
|
||||
+ "NextObj {} on {}", nextId, deviceId),
|
||||
(objective, error) -> {
|
||||
log.warn("createGroupFromMacVlan failed to install NextObj {} on {}: {}", nextId, deviceId, error);
|
||||
srManager.invalidateNextObj(objective.id());
|
||||
});
|
||||
NextObjective nextObj = nextObjBuilder.add(context);
|
||||
flowObjectiveService.next(deviceId, nextObj);
|
||||
log.debug("createGroupFromMacVlan: Submited next objective {} in device {} "
|
||||
+ "for host {}/{}", nextId, deviceId, macAddr, vlanId);
|
||||
|
||||
macVlanNextObjStore.put(key, nextId);
|
||||
return nextId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create simple next objective for a single port. The treatments can include
|
||||
* all outgoing actions that need to happen on the packet.
|
||||
@ -1257,6 +1350,7 @@ public class DefaultGroupHandler {
|
||||
portNextObjStore.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes groups for the next objective ID given.
|
||||
*
|
||||
@ -1401,6 +1495,94 @@ public class DefaultGroupHandler {
|
||||
flowObjectiveService.next(deviceId, nextObjBuilder.modify(context));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next ID for the given host port from the store.
|
||||
*
|
||||
* @param hostMac mac of host for which Next ID is required.
|
||||
* @param hostVlanId vlan of host for which Next ID is required.
|
||||
* @param port port of device for which next ID is required.
|
||||
* @return next objective ID or -1 if an error occurred during retrieval
|
||||
*/
|
||||
public int getNextIdForHostPort(MacAddress hostMac, VlanId hostVlanId, PortNumber port) {
|
||||
|
||||
MacAddress deviceMac;
|
||||
try {
|
||||
deviceMac = deviceConfig.getDeviceMac(deviceId);
|
||||
} catch (DeviceConfigNotFoundException e) {
|
||||
log.warn(e.getMessage() + " in getNextIdForHostPort");
|
||||
return -1;
|
||||
}
|
||||
|
||||
TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
|
||||
tbuilder.deferred()
|
||||
.setEthDst(hostMac)
|
||||
.setEthSrc(deviceMac)
|
||||
.setVlanId(hostVlanId)
|
||||
.setOutput(port);
|
||||
|
||||
TrafficSelector metadata =
|
||||
DefaultTrafficSelector.builder().matchVlanId(hostVlanId).build();
|
||||
|
||||
int nextId = getMacVlanNextObjectiveId(hostMac, hostVlanId,
|
||||
tbuilder.build(), metadata, true);
|
||||
|
||||
log.debug("getNextId : hostMac {}, deviceMac {}, port {}, hostVlanId {} Treatment {} Meta {} nextId {} ",
|
||||
hostMac, deviceMac, port, hostVlanId, tbuilder.build(), metadata, nextId);
|
||||
|
||||
return nextId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the next objective for the given nextId .
|
||||
*
|
||||
* @param hostMac mac of host for which Next obj is to be updated.
|
||||
* @param hostVlanId vlan of host for which Next obj is to be updated.
|
||||
* @param port port with which to update the Next Obj.
|
||||
* @param nextId of Next Obj which needs to be updated.
|
||||
*/
|
||||
public void updateL3UcastGroupBucket(MacAddress hostMac, VlanId hostVlanId, PortNumber port, int nextId) {
|
||||
|
||||
MacAddress deviceMac;
|
||||
try {
|
||||
deviceMac = deviceConfig.getDeviceMac(deviceId);
|
||||
} catch (DeviceConfigNotFoundException e) {
|
||||
log.warn(e.getMessage() + " in updateL3UcastGroupBucket");
|
||||
return;
|
||||
}
|
||||
|
||||
TrafficSelector metadata =
|
||||
DefaultTrafficSelector.builder().matchVlanId(hostVlanId).build();
|
||||
|
||||
TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
|
||||
tbuilder.deferred()
|
||||
.setEthDst(hostMac)
|
||||
.setEthSrc(deviceMac)
|
||||
.setVlanId(hostVlanId)
|
||||
.setOutput(port);
|
||||
|
||||
log.debug(" update L3Ucast : deviceMac {}, port {}, host {}/{}, nextid {}, Treatment {} Meta {}",
|
||||
deviceMac, port, hostMac, hostVlanId, nextId, tbuilder.build(), metadata);
|
||||
|
||||
NextObjective.Builder nextObjBuilder = DefaultNextObjective
|
||||
.builder().withId(nextId)
|
||||
.withType(NextObjective.Type.SIMPLE).fromApp(appId)
|
||||
.addTreatment(tbuilder.build())
|
||||
.withMeta(metadata);
|
||||
|
||||
ObjectiveContext context = new DefaultObjectiveContext(
|
||||
(objective) -> log.debug(" NextId {} successfully updated host {} vlan {} with port {}",
|
||||
nextId, hostMac, hostVlanId, port),
|
||||
(objective, error) -> {
|
||||
log.warn(" NextId {} failed to update host {} vlan {} with port {}, error : {}",
|
||||
nextId, hostMac, hostVlanId, port, error);
|
||||
srManager.invalidateNextObj(objective.id());
|
||||
});
|
||||
|
||||
NextObjective nextObj = nextObjBuilder.modify(context);
|
||||
flowObjectiveService.next(deviceId, nextObj);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a single port to the L2FG or removes it from the L2FG.
|
||||
*
|
||||
|
||||
@ -21,6 +21,8 @@ import java.util.Objects;
|
||||
import org.onosproject.net.DeviceId;
|
||||
import org.onosproject.segmentrouting.grouphandler.DestinationSet;
|
||||
|
||||
import static com.google.common.base.MoreObjects.toStringHelper;
|
||||
|
||||
/**
|
||||
* Key of Destination set next objective store.
|
||||
*/
|
||||
@ -84,6 +86,9 @@ public class DestinationSetNextObjectiveStoreKey {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Device: " + deviceId + " " + ds;
|
||||
return toStringHelper(getClass())
|
||||
.add("deviceId", deviceId)
|
||||
.add("ds", ds)
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2019-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.segmentrouting.storekey;
|
||||
|
||||
import org.onlab.packet.VlanId;
|
||||
import org.onlab.packet.MacAddress;
|
||||
import org.onosproject.net.DeviceId;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import static com.google.common.base.MoreObjects.toStringHelper;
|
||||
|
||||
/**
|
||||
* Key of Device/Vlan/MacAddr to NextObjective store.
|
||||
*/
|
||||
public class MacVlanNextObjectiveStoreKey {
|
||||
private final DeviceId deviceId;
|
||||
private final MacAddress macAddr;
|
||||
private final VlanId vlanId;
|
||||
|
||||
/**
|
||||
* Constructs the key of the next objective store.
|
||||
*
|
||||
* @param deviceId device ID
|
||||
* @param macAddr mac of host
|
||||
* @param vlanId vlan of host
|
||||
*/
|
||||
public MacVlanNextObjectiveStoreKey(DeviceId deviceId, MacAddress macAddr, VlanId vlanId) {
|
||||
this.deviceId = deviceId;
|
||||
this.macAddr = macAddr;
|
||||
this.vlanId = vlanId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets device id in this MacVlanNextObjectiveStoreKey.
|
||||
*
|
||||
* @return device id
|
||||
*/
|
||||
public DeviceId deviceId() {
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets vlan information in this MacVlanNextObjectiveStoreKey.
|
||||
*
|
||||
* @return vlan information
|
||||
*/
|
||||
public VlanId vlanId() {
|
||||
return vlanId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets mac information in this MacVlanNextObjectiveStoreKey.
|
||||
*
|
||||
* @return mac information
|
||||
*/
|
||||
public MacAddress macAddr() {
|
||||
return macAddr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof MacVlanNextObjectiveStoreKey)) {
|
||||
return false;
|
||||
}
|
||||
MacVlanNextObjectiveStoreKey that =
|
||||
(MacVlanNextObjectiveStoreKey) o;
|
||||
return (Objects.equals(this.deviceId, that.deviceId) &&
|
||||
Objects.equals(this.vlanId, that.vlanId) &&
|
||||
Objects.equals(this.macAddr, that.macAddr));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(deviceId, vlanId, macAddr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toStringHelper(getClass())
|
||||
.add("deviceId", deviceId)
|
||||
.add("vlanId", vlanId)
|
||||
.add("macAddr", macAddr)
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
@ -22,6 +22,8 @@ import org.onosproject.net.flow.TrafficTreatment;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import static com.google.common.base.MoreObjects.toStringHelper;
|
||||
|
||||
/**
|
||||
* Key of Device/Port to NextObjective store.
|
||||
*
|
||||
@ -111,8 +113,11 @@ public class PortNextObjectiveStoreKey {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ConnectPoint: " + deviceId + "/" + portNum +
|
||||
" Treatment: " + treatment +
|
||||
" Meta: " + meta;
|
||||
return toStringHelper(getClass())
|
||||
.add("deviceId", deviceId)
|
||||
.add("portNum", portNum)
|
||||
.add("treatment", treatment)
|
||||
.add("meta", meta)
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,6 +21,8 @@ import org.onosproject.net.DeviceId;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import static com.google.common.base.MoreObjects.toStringHelper;
|
||||
|
||||
/**
|
||||
* Key of VLAN to NextObjective store.
|
||||
*/
|
||||
@ -79,6 +81,9 @@ public class VlanNextObjectiveStoreKey {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "deviceId: " + deviceId + " vlanId: " + vlanId;
|
||||
return toStringHelper(getClass())
|
||||
.add("deviceId", deviceId)
|
||||
.add("vlanId", vlanId)
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@ -563,7 +563,7 @@ public class HostHandlerTest {
|
||||
// We should expect only one bridging flow and one routing flow programmed on 1A
|
||||
mockDefaultRoutingHandler.populateBridging(DEV3, P2, HOST_MAC, HOST_VLAN_UNTAGGED);
|
||||
expectLastCall().times(1);
|
||||
mockDefaultRoutingHandler.populateRoute(DEV3, HOST_IP11.toIpPrefix(), HOST_MAC, HOST_VLAN_UNTAGGED, P2);
|
||||
mockDefaultRoutingHandler.populateRoute(DEV3, HOST_IP11.toIpPrefix(), HOST_MAC, HOST_VLAN_UNTAGGED, P2, true);
|
||||
expectLastCall().times(1);
|
||||
replay(mockDefaultRoutingHandler);
|
||||
|
||||
|
||||
@ -38,7 +38,7 @@ public class MockRoutingRulePopulator extends RoutingRulePopulator {
|
||||
|
||||
@Override
|
||||
public void populateRoute(DeviceId deviceId, IpPrefix prefix,
|
||||
MacAddress hostMac, VlanId hostVlanId, PortNumber outPort) {
|
||||
MacAddress hostMac, VlanId hostVlanId, PortNumber outPort, boolean directHost) {
|
||||
MockRoutingTableKey rtKey = new MockRoutingTableKey(deviceId, prefix);
|
||||
MockRoutingTableValue rtValue = new MockRoutingTableValue(outPort, hostMac, hostVlanId);
|
||||
routingTable.put(rtKey, rtValue);
|
||||
@ -46,9 +46,9 @@ public class MockRoutingRulePopulator extends RoutingRulePopulator {
|
||||
|
||||
@Override
|
||||
public void revokeRoute(DeviceId deviceId, IpPrefix prefix,
|
||||
MacAddress hostMac, VlanId hostVlanId, PortNumber outPort) {
|
||||
MacAddress hostMac, VlanId hostVlanId, PortNumber outPort, boolean directHost) {
|
||||
MockRoutingTableKey rtKey = new MockRoutingTableKey(deviceId, prefix);
|
||||
MockRoutingTableValue rtValue = new MockRoutingTableValue(outPort, hostMac, hostVlanId);
|
||||
routingTable.remove(rtKey, rtValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -595,4 +595,4 @@ public class RouteHandlerTest {
|
||||
|
||||
verify(srManager.deviceConfiguration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -854,7 +854,7 @@ public class Ofdpa2GroupHandler {
|
||||
}
|
||||
}
|
||||
if (portNum == null) {
|
||||
log.warn("Can't find output port for the bucket {}.", treatment);
|
||||
log.debug("Can't find output port for the bucket {}.", treatment);
|
||||
continue;
|
||||
}
|
||||
// assemble info for l2 interface group
|
||||
@ -880,12 +880,89 @@ public class Ofdpa2GroupHandler {
|
||||
log.debug("Trying L2-Interface: device:{} gid:{} gkey:{} nextid:{}",
|
||||
deviceId, Integer.toHexString(l2InterfaceGroupId),
|
||||
l2InterfaceGroupKey, nextObj.id());
|
||||
|
||||
groupInfoBuilder.add(new GroupInfo(l2InterfaceGroupDescription,
|
||||
l2InterfaceGroupDescription));
|
||||
}
|
||||
return groupInfoBuilder.build();
|
||||
}
|
||||
|
||||
private GroupInfo prepareL3UnicastGroup(NextObjective nextObj, NextGroup next) {
|
||||
|
||||
ImmutableList.Builder<GroupInfo> groupInfoBuilder = ImmutableList.builder();
|
||||
TrafficTreatment treatment = nextObj.next().iterator().next();
|
||||
|
||||
VlanId assignedVlan = readVlanFromSelector(nextObj.meta());
|
||||
if (assignedVlan == null) {
|
||||
log.warn("VLAN ID required by next obj is missing. Abort.");
|
||||
return null;
|
||||
}
|
||||
|
||||
List<GroupInfo> l2GroupInfos = prepareL2InterfaceGroup(nextObj, assignedVlan);
|
||||
GroupDescription l2InterfaceGroupDesc = l2GroupInfos.get(0).innerMostGroupDesc();
|
||||
GroupKey l2groupkey = l2InterfaceGroupDesc.appCookie();
|
||||
|
||||
TrafficTreatment.Builder outerTtb = DefaultTrafficTreatment.builder();
|
||||
VlanId vlanid = null;
|
||||
MacAddress srcMac;
|
||||
MacAddress dstMac;
|
||||
for (Instruction ins : treatment.allInstructions()) {
|
||||
if (ins.type() == Instruction.Type.L2MODIFICATION) {
|
||||
L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
|
||||
switch (l2ins.subtype()) {
|
||||
case ETH_DST:
|
||||
dstMac = ((L2ModificationInstruction.ModEtherInstruction) l2ins).mac();
|
||||
outerTtb.setEthDst(dstMac);
|
||||
break;
|
||||
case ETH_SRC:
|
||||
srcMac = ((L2ModificationInstruction.ModEtherInstruction) l2ins).mac();
|
||||
outerTtb.setEthSrc(srcMac);
|
||||
break;
|
||||
case VLAN_ID:
|
||||
vlanid = ((L2ModificationInstruction.ModVlanIdInstruction) l2ins).vlanId();
|
||||
outerTtb.setVlanId(vlanid);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
log.debug("Driver does not handle this type of TrafficTreatment"
|
||||
+ " instruction in l2l3chain: {} - {}", ins.type(), ins);
|
||||
}
|
||||
}
|
||||
|
||||
GroupId l2groupId = new GroupId(l2InterfaceGroupDesc.givenGroupId());
|
||||
outerTtb.group(l2groupId);
|
||||
|
||||
// we need the top level group's key to point the flow to it
|
||||
List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
|
||||
GroupKey l3groupkey = gkeys.get(0).peekFirst();
|
||||
GroupId grpId = groupService.getGroup(deviceId, l3groupkey).id();
|
||||
int l3groupId = grpId.id();
|
||||
|
||||
// create the l3unicast group description to wait for the
|
||||
// l2 interface group to be processed
|
||||
GroupBucket l3UnicastGroupBucket = DefaultGroupBucket.createIndirectGroupBucket(outerTtb.build());
|
||||
|
||||
GroupDescription l3UnicastGroupDescription = new DefaultGroupDescription(deviceId,
|
||||
GroupDescription.Type.INDIRECT,
|
||||
new GroupBuckets(Collections.singletonList(
|
||||
l3UnicastGroupBucket)), l3groupkey,
|
||||
l3groupId, nextObj.appId());
|
||||
|
||||
// store l2groupkey with the groupChainElem for the outer-group that depends on it
|
||||
GroupChainElem gce = new GroupChainElem(l3UnicastGroupDescription, 1, false, deviceId);
|
||||
updatePendingGroups(l2groupkey, gce);
|
||||
|
||||
log.debug("Trying L3-Interface: device:{} gid:{} gkey:{} nextid:{}",
|
||||
deviceId, Integer.toHexString(l3groupId), l3groupkey, nextObj.id());
|
||||
|
||||
groupInfoBuilder.add(new GroupInfo(l2InterfaceGroupDesc,
|
||||
l3UnicastGroupDescription));
|
||||
|
||||
return groupInfoBuilder.build().iterator().next();
|
||||
}
|
||||
|
||||
private void createL2FloodGroup(NextObjective nextObj, VlanId vlanId,
|
||||
List<GroupInfo> groupInfos) {
|
||||
// assemble info for l2 flood group. Since there can be only one flood
|
||||
@ -1794,6 +1871,64 @@ public class Ofdpa2GroupHandler {
|
||||
flowObjectiveStore.removeNextGroup(nextObjective.id());
|
||||
}
|
||||
|
||||
/**
|
||||
* modifies group with next objective.
|
||||
*
|
||||
* @param nextObjective the NextObjective
|
||||
* @param nextGroup the NextGroup
|
||||
*/
|
||||
protected void modifyBucketFromGroup(NextObjective nextObjective, NextGroup nextGroup) {
|
||||
switch (nextObjective.type()) {
|
||||
case SIMPLE:
|
||||
Collection<TrafficTreatment> treatments = nextObjective.next();
|
||||
if (treatments.size() != 1) {
|
||||
log.error("Next Objectives of type Simple should only have a "
|
||||
+ "single Traffic Treatment. Next Objective Id:{}",
|
||||
nextObjective.id());
|
||||
fail(nextObjective, ObjectiveError.BADPARAMS);
|
||||
return;
|
||||
}
|
||||
modifySimpleNextObjective(nextObjective, nextGroup);
|
||||
break;
|
||||
default:
|
||||
fail(nextObjective, ObjectiveError.UNKNOWN);
|
||||
log.warn("Unknown next objective type {}", nextObjective.type());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* As per the OFDPA 2.0 TTP, packets are sent out of ports by using
|
||||
* a chain of groups. The simple Next Objective passed in by the application
|
||||
* is broken up into a group chain. The following chains can be modified
|
||||
* depending on the parameters in the Next Objective.
|
||||
* 1. L2 Interface group (no chaining)
|
||||
* 2. L3 Unicast group -> L2 Interface group
|
||||
*
|
||||
* @param nextObj the nextObjective of type SIMPLE
|
||||
*/
|
||||
private void modifySimpleNextObjective(NextObjective nextObj, NextGroup nextGroup) {
|
||||
TrafficTreatment treatment = nextObj.next().iterator().next();
|
||||
// determine if plain L2 or L3->L2 chain
|
||||
boolean plainL2 = true;
|
||||
for (Instruction ins : treatment.allInstructions()) {
|
||||
if (ins.type() == Instruction.Type.L2MODIFICATION) {
|
||||
L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
|
||||
if (l2ins.subtype() == L2ModificationInstruction.L2SubType.ETH_DST ||
|
||||
l2ins.subtype() == L2ModificationInstruction.L2SubType.ETH_SRC ||
|
||||
l2ins.subtype() == L2ModificationInstruction.L2SubType.VLAN_ID) {
|
||||
plainL2 = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (plainL2) {
|
||||
modifyBucketInL2Group(nextObj, nextGroup);
|
||||
} else {
|
||||
modifyBucketInL3Group(nextObj, nextGroup);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Modify buckets in the L2 interface group.
|
||||
*
|
||||
@ -1802,13 +1937,8 @@ public class Ofdpa2GroupHandler {
|
||||
* @param next the representation of the existing group-chains for this next
|
||||
* objective, from which the innermost group buckets to remove are determined
|
||||
*/
|
||||
protected void modifyBucketFromGroup(NextObjective nextObjective, NextGroup next) {
|
||||
if (nextObjective.type() != NextObjective.Type.SIMPLE) {
|
||||
log.warn("ModifyBucketFromGroup cannot be applied to nextType:{} in dev:{} for next:{}",
|
||||
nextObjective.type(), deviceId, nextObjective.id());
|
||||
fail(nextObjective, ObjectiveError.UNSUPPORTED);
|
||||
return;
|
||||
}
|
||||
|
||||
protected void modifyBucketInL2Group(NextObjective nextObjective, NextGroup next) {
|
||||
|
||||
VlanId assignedVlan = readVlanFromSelector(nextObjective.meta());
|
||||
if (assignedVlan == null) {
|
||||
@ -1842,8 +1972,54 @@ public class Ofdpa2GroupHandler {
|
||||
new OfdpaNextGroup(modifiedGroupKeys,
|
||||
nextObjective));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected void modifyBucketInL3Group(NextObjective nextObjective, NextGroup next) {
|
||||
|
||||
//get l3 group
|
||||
GroupInfo groupInfo = prepareL3UnicastGroup(nextObjective, next);
|
||||
if (groupInfo == null) {
|
||||
log.warn("Null groupInfo retrieved for next obj. Abort.");
|
||||
fail(nextObjective, ObjectiveError.BADPARAMS);
|
||||
return;
|
||||
}
|
||||
|
||||
GroupDescription l3UnicastGroupDesc = groupInfo.nextGroupDesc();
|
||||
|
||||
// Replace group bucket for L3 UC interface group
|
||||
groupService.setBucketsForGroup(deviceId, l3UnicastGroupDesc.appCookie(),
|
||||
l3UnicastGroupDesc.buckets(), l3UnicastGroupDesc.appCookie(),
|
||||
l3UnicastGroupDesc.appId());
|
||||
|
||||
// create object for local and distributed storage
|
||||
Deque<GroupKey> gkeyChain = new ArrayDeque<>();
|
||||
gkeyChain.addFirst(groupInfo.innerMostGroupDesc().appCookie());
|
||||
gkeyChain.addFirst(groupInfo.nextGroupDesc().appCookie());
|
||||
List<Deque<GroupKey>> allGroupKeys = Lists.newArrayList();
|
||||
allGroupKeys.add(gkeyChain);
|
||||
OfdpaNextGroup ofdpaGrp = new OfdpaNextGroup(allGroupKeys, nextObjective);
|
||||
// store l3groupkey with the ofdpaNextGroup for the nextObjective that depends on it
|
||||
updatePendingNextObjective(groupInfo.nextGroupDesc().appCookie(), ofdpaGrp);
|
||||
|
||||
// update store - synchronize access as there may be multiple threads
|
||||
// trying to update bucket from the same group, each with its own
|
||||
// potentially stale copy of allActiveKeys
|
||||
synchronized (flowObjectiveStore) {
|
||||
|
||||
List<Deque<GroupKey>> modifiedGroupKeys = Lists.newArrayList();
|
||||
ArrayDeque<GroupKey> top = new ArrayDeque<>();
|
||||
top.add(l3UnicastGroupDesc.appCookie());
|
||||
top.add(groupInfo.innerMostGroupDesc().appCookie()); //l2 group key
|
||||
modifiedGroupKeys.add(top);
|
||||
|
||||
flowObjectiveStore.putNextGroup(nextObjective.id(),
|
||||
new OfdpaNextGroup(modifiedGroupKeys,
|
||||
nextObjective));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks existing buckets in {@link NextGroup} to verify if they match
|
||||
* the buckets in the given {@link NextObjective}. Adds or removes buckets
|
||||
|
||||
@ -425,8 +425,8 @@ public class Ofdpa2Pipeline extends AbstractHandlerBehaviour implements Pipeline
|
||||
nextObjective.id(), deviceId);
|
||||
return;
|
||||
}
|
||||
log.debug("Processing NextObjective id {} in dev {} - modify bucket",
|
||||
nextObjective.id(), deviceId);
|
||||
log.debug("Processing NextObjective id {} in dev {} group {} - modify bucket",
|
||||
nextObjective.id(), deviceId, nextGroup);
|
||||
groupHandler.modifyBucketFromGroup(nextObjective, nextGroup);
|
||||
break;
|
||||
case VERIFY:
|
||||
|
||||
@ -30,6 +30,7 @@
|
||||
<suppress files="org.onlab.packet.*" checks="AbbreviationAsWordInName" />
|
||||
<suppress files="org.onlab.jdvue.*" checks="AbbreviationAsWordInName" />
|
||||
<suppress files="org.onosproject.driver.pipeline.*" checks="AbbreviationAsWordInName" />
|
||||
<suppress files="org.onosproject.driver.pipeline.ofdpa.Ofdpa2GroupHandler.java" checks="FileLength" />
|
||||
<suppress files="org.onosproject.segmentrouting.*" checks="AbbreviationAsWordInName" />
|
||||
|
||||
<!-- These files carry AT&T copyrights -->
|
||||
|
||||
@ -109,6 +109,7 @@ CLI_COMMANDS=(
|
||||
"sr-next-vlan"
|
||||
"sr-next-pw"
|
||||
"sr-next-xconnect"
|
||||
"sr-next-mac-vlan"
|
||||
"dhcp-relay"
|
||||
|
||||
"mcast-host-routes"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user