aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/onos/apps/segmentrouting/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/onos/apps/segmentrouting/src/main')
-rw-r--r--framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/ArpHandler.java26
-rw-r--r--framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java1
-rw-r--r--framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java2
-rw-r--r--framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IpHandler.java2
-rw-r--r--framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java63
-rw-r--r--framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java146
-rw-r--r--framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/TunnelHandler.java2
-rw-r--r--framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/config/DeviceConfiguration.java45
-rw-r--r--framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/config/SegmentRoutingConfig.java219
-rw-r--r--framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultEdgeGroupHandler.java6
-rw-r--r--framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java139
-rw-r--r--framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultTransitGroupHandler.java6
-rw-r--r--framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupHandler.java6
-rw-r--r--framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PortNextObjectiveStoreKey.java77
14 files changed, 560 insertions, 180 deletions
diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/ArpHandler.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/ArpHandler.java
index 2c6412cf..7f4bcb15 100644
--- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/ArpHandler.java
+++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/ArpHandler.java
@@ -107,7 +107,7 @@ public class ArpHandler {
vlanId);
// ARP request for router. Send ARP reply.
- if (isArpReqForRouter(deviceId, arpRequest)) {
+ if (isArpForRouter(deviceId, arpRequest)) {
Ip4Address targetAddress = Ip4Address.valueOf(arpRequest.getTargetProtocolAddress());
sendArpResponse(arpRequest, config.getRouterMacForAGatewayIp(targetAddress), vlanId);
} else {
@@ -130,7 +130,7 @@ public class ArpHandler {
vlanId);
// ARP reply for router. Process all pending IP packets.
- if (isArpReqForRouter(deviceId, arpReply)) {
+ if (isArpForRouter(deviceId, arpReply)) {
Ip4Address hostIpAddress = Ip4Address.valueOf(arpReply.getSenderProtocolAddress());
srManager.ipHandler.forwardPackets(deviceId, hostIpAddress);
} else {
@@ -141,7 +141,8 @@ public class ArpHandler {
// ARP reply for unknown host, Flood in the subnet.
} else {
// Don't flood to non-edge ports
- if (vlanId.equals(VlanId.vlanId(srManager.ASSIGNED_VLAN_NO_SUBNET))) {
+ if (vlanId.equals(
+ VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET))) {
return;
}
removeVlanAndFlood(payload, inPort);
@@ -150,14 +151,21 @@ public class ArpHandler {
}
- private boolean isArpReqForRouter(DeviceId deviceId, ARP arpRequest) {
- Set<Ip4Address> gatewayIpAddresses = config.getPortIPs(deviceId);
- if (gatewayIpAddresses != null) {
- Ip4Address targetProtocolAddress = Ip4Address.valueOf(arpRequest
- .getTargetProtocolAddress());
- if (gatewayIpAddresses.contains(targetProtocolAddress)) {
+ private boolean isArpForRouter(DeviceId deviceId, ARP arpMsg) {
+ Ip4Address targetProtocolAddress = Ip4Address.valueOf(
+ arpMsg.getTargetProtocolAddress());
+ Set<Ip4Address> gatewayIpAddresses = null;
+ try {
+ if (targetProtocolAddress.equals(config.getRouterIp(deviceId))) {
return true;
}
+ gatewayIpAddresses = config.getPortIPs(deviceId);
+ } catch (DeviceConfigNotFoundException e) {
+ log.warn(e.getMessage() + " Aborting check for router IP in processing arp");
+ }
+ if (gatewayIpAddresses != null &&
+ gatewayIpAddresses.contains(targetProtocolAddress)) {
+ return true;
}
return false;
}
diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java
index 99225874..e6451653 100644
--- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java
+++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java
@@ -513,6 +513,7 @@ public class DefaultRoutingHandler {
public void populatePortAddressingRules(DeviceId deviceId) {
rulePopulator.populateRouterMacVlanFilters(deviceId);
rulePopulator.populateRouterIpPunts(deviceId);
+ rulePopulator.populateArpPunts(deviceId);
}
/**
diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java
index eb3b3fd5..d1dc8ddc 100644
--- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java
+++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java
@@ -88,10 +88,10 @@ public class IcmpHandler {
(destinationAddress.equals(routerIpAddress) ||
gatewayIpAddresses.contains(destinationAddress))) {
sendICMPResponse(ethernet, connectPoint);
- // TODO: do we need to set the flow rule again ??
// ICMP for any known host
} else if (!srManager.hostService.getHostsByIp(destinationAddress).isEmpty()) {
+ // TODO: known host packet should not be coming to controller - resend flows?
srManager.ipHandler.forwardPackets(deviceId, destinationAddress);
// ICMP for an unknown host in the subnet of the router
diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IpHandler.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IpHandler.java
index b1682e77..d6a9dcfc 100644
--- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IpHandler.java
+++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IpHandler.java
@@ -98,7 +98,7 @@ public class IpHandler {
*/
public void addToPacketBuffer(IPv4 ipPacket) {
- // Better not buffer TPC packets due to out-of-order packet transfer
+ // Better not buffer TCP packets due to out-of-order packet transfer
if (ipPacket.getProtocol() == IPv4.PROTOCOL_TCP) {
return;
}
diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
index a07a15d2..d4aa770c 100644
--- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
+++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
@@ -147,20 +147,34 @@ public class RoutingRulePopulator {
TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
- sbuilder.matchIPDst(IpPrefix.valueOf(hostIp, IpPrefix.MAX_INET_MASK_LENGTH));
sbuilder.matchEthType(Ethernet.TYPE_IPV4);
+ sbuilder.matchIPDst(IpPrefix.valueOf(hostIp, IpPrefix.MAX_INET_MASK_LENGTH));
+ TrafficSelector selector = sbuilder.build();
tbuilder.deferred()
.setEthDst(hostMac)
.setEthSrc(deviceMac)
.setOutput(outPort);
-
TrafficTreatment treatment = tbuilder.build();
- TrafficSelector selector = sbuilder.build();
+
+ // All forwarding is via Groups. Drivers can re-purpose to flow-actions if needed.
+ // for switch pipelines that need it, provide outgoing vlan as metadata
+ VlanId outvlan = null;
+ Ip4Prefix subnet = srManager.deviceConfiguration.getPortSubnet(deviceId, outPort);
+ if (subnet == null) {
+ outvlan = VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET);
+ } else {
+ outvlan = srManager.getSubnetAssignedVlanId(deviceId, subnet);
+ }
+ TrafficSelector meta = DefaultTrafficSelector.builder()
+ .matchVlanId(outvlan).build();
+ int portNextObjId = srManager.getPortNextObjectiveId(deviceId, outPort,
+ treatment, meta);
return DefaultForwardingObjective.builder()
+ .withSelector(selector)
+ .nextStep(portNextObjId)
.fromApp(srManager.appId).makePermanent()
- .withSelector(selector).withTreatment(treatment)
.withPriority(100).withFlag(ForwardingObjective.Flag.SPECIFIC);
}
@@ -454,7 +468,7 @@ public class RoutingRulePopulator {
if (srManager.mastershipService.isLocalMaster(deviceId)) {
TrafficTreatment tt = DefaultTrafficTreatment.builder()
.pushVlan().setVlanId(assignedVlan).build();
- fob.setMeta(tt);
+ fob.withMeta(tt);
}
fob.permit().fromApp(srManager.appId);
srManager.flowObjectiveService.
@@ -511,6 +525,39 @@ public class RoutingRulePopulator {
}
/**
+ * Creates a forwarding objective to punt all IP packets, destined to the
+ * router's port IP addresses, to the controller. Note that the input
+ * port should not be matched on, as these packets can come from any input.
+ * Furthermore, these are applied only by the master instance.
+ *
+ * @param deviceId the switch dpid for the router
+ */
+ public void populateArpPunts(DeviceId deviceId) {
+ if (!srManager.mastershipService.isLocalMaster(deviceId)) {
+ log.debug("Not installing port-IP punts - not the master for dev:{} ",
+ deviceId);
+ return;
+ }
+
+ ForwardingObjective.Builder puntArp = DefaultForwardingObjective.builder();
+ TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
+ TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
+ sbuilder.matchEthType(Ethernet.TYPE_ARP);
+ tbuilder.setOutput(PortNumber.CONTROLLER);
+ puntArp.withSelector(sbuilder.build());
+ puntArp.withTreatment(tbuilder.build());
+ puntArp.withFlag(Flag.VERSATILE)
+ .withPriority(HIGHEST_PRIORITY)
+ .makePermanent()
+ .fromApp(srManager.appId);
+ log.debug("Installing forwarding objective to punt ARPs");
+ srManager.flowObjectiveService.
+ forward(deviceId,
+ puntArp.add(new SRObjectiveContext(deviceId,
+ SRObjectiveContext.ObjectiveType.FORWARDING)));
+ }
+
+ /**
* Populates a forwarding objective to send packets that miss other high
* priority Bridging Table entries to a group that contains all ports of
* its subnet.
@@ -526,6 +573,12 @@ public class RoutingRulePopulator {
int nextId = srManager.getSubnetNextObjectiveId(deviceId, subnet);
VlanId vlanId = srManager.getSubnetAssignedVlanId(deviceId, subnet);
+ if (nextId < 0 || vlanId == null) {
+ log.error("Cannot install subnet broadcast rule in dev:{} due"
+ + "to vlanId:{} or nextId:{}", vlanId, nextId);
+ return;
+ }
+
/* Driver should treat objective with MacAddress.NONE as the
* subnet broadcast rule
*/
diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
index f6bf649c..62722f02 100644
--- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
+++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
@@ -57,6 +57,7 @@ import org.onosproject.segmentrouting.config.SegmentRoutingConfig;
import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler;
import org.onosproject.segmentrouting.grouphandler.NeighborSet;
import org.onosproject.segmentrouting.grouphandler.NeighborSetNextObjectiveStoreKey;
+import org.onosproject.segmentrouting.grouphandler.PortNextObjectiveStoreKey;
import org.onosproject.mastership.MastershipService;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
@@ -97,7 +98,6 @@ import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
-@SuppressWarnings("ALL")
@Service
@Component(immediate = true)
public class SegmentRoutingManager implements SegmentRoutingService {
@@ -150,21 +150,27 @@ public class SegmentRoutingManager implements SegmentRoutingService {
private ScheduledExecutorService executorService = Executors
.newScheduledThreadPool(1);
+ @SuppressWarnings("unused")
private static ScheduledFuture<?> eventHandlerFuture = null;
+ @SuppressWarnings("rawtypes")
private ConcurrentLinkedQueue<Event> eventQueue = new ConcurrentLinkedQueue<Event>();
private Map<DeviceId, DefaultGroupHandler> groupHandlerMap =
new ConcurrentHashMap<DeviceId, DefaultGroupHandler>();
// Per device next objective ID store with (device id + neighbor set) as key
private EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey, Integer>
nsNextObjStore = null;
+ // Per device next objective ID store with (device id + subnet) as key
private EventuallyConsistentMap<SubnetNextObjectiveStoreKey, Integer>
subnetNextObjStore = null;
- private EventuallyConsistentMap<String, Tunnel> tunnelStore = null;
- private EventuallyConsistentMap<String, Policy> policyStore = null;
+ // Per device next objective ID store with (device id + port) as key
+ private EventuallyConsistentMap<PortNextObjectiveStoreKey, Integer>
+ portNextObjStore = null;
// Per device, per-subnet assigned-vlans store, with (device id + subnet
// IPv4 prefix) as key
private EventuallyConsistentMap<SubnetAssignedVidStoreKey, VlanId>
subnetVidStore = null;
+ private EventuallyConsistentMap<String, Tunnel> tunnelStore = null;
+ private EventuallyConsistentMap<String, Policy> policyStore = null;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected StorageService storageService;
@@ -175,6 +181,7 @@ public class SegmentRoutingManager implements SegmentRoutingService {
private final InternalConfigListener cfgListener =
new InternalConfigListener(this);
+ @SuppressWarnings({ "unchecked", "rawtypes" })
private final ConfigFactory cfgFactory =
new ConfigFactory(SubjectFactories.DEVICE_SUBJECT_FACTORY,
SegmentRoutingConfig.class,
@@ -185,7 +192,7 @@ public class SegmentRoutingManager implements SegmentRoutingService {
}
};
- private final HostListener hostListener = new InternalHostListener();
+ private final InternalHostListener hostListener = new InternalHostListener();
private Object threadSchedulerLock = new Object();
private static int numOfEventsQueued = 0;
@@ -228,7 +235,6 @@ public class SegmentRoutingManager implements SegmentRoutingService {
log.debug("Creating EC map nsnextobjectivestore");
EventuallyConsistentMapBuilder<NeighborSetNextObjectiveStoreKey, Integer>
nsNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
-
nsNextObjStore = nsNextObjMapBuilder
.withName("nsnextobjectivestore")
.withSerializer(kryoBuilder)
@@ -239,16 +245,23 @@ public class SegmentRoutingManager implements SegmentRoutingService {
log.debug("Creating EC map subnetnextobjectivestore");
EventuallyConsistentMapBuilder<SubnetNextObjectiveStoreKey, Integer>
subnetNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
-
subnetNextObjStore = subnetNextObjMapBuilder
.withName("subnetnextobjectivestore")
.withSerializer(kryoBuilder)
.withTimestampProvider((k, v) -> new WallClockTimestamp())
.build();
+ log.debug("Creating EC map subnetnextobjectivestore");
+ EventuallyConsistentMapBuilder<PortNextObjectiveStoreKey, Integer>
+ portNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
+ portNextObjStore = portNextObjMapBuilder
+ .withName("portnextobjectivestore")
+ .withSerializer(kryoBuilder)
+ .withTimestampProvider((k, v) -> new WallClockTimestamp())
+ .build();
+
EventuallyConsistentMapBuilder<String, Tunnel> tunnelMapBuilder =
storageService.eventuallyConsistentMapBuilder();
-
tunnelStore = tunnelMapBuilder
.withName("tunnelstore")
.withSerializer(kryoBuilder)
@@ -257,7 +270,6 @@ public class SegmentRoutingManager implements SegmentRoutingService {
EventuallyConsistentMapBuilder<String, Policy> policyMapBuilder =
storageService.eventuallyConsistentMapBuilder();
-
policyStore = policyMapBuilder
.withName("policystore")
.withSerializer(kryoBuilder)
@@ -266,7 +278,6 @@ public class SegmentRoutingManager implements SegmentRoutingService {
EventuallyConsistentMapBuilder<SubnetAssignedVidStoreKey, VlanId>
subnetVidStoreMapBuilder = storageService.eventuallyConsistentMapBuilder();
-
subnetVidStore = subnetVidStoreMapBuilder
.withName("subnetvidstore")
.withSerializer(kryoBuilder)
@@ -425,8 +436,7 @@ public class SegmentRoutingManager implements SegmentRoutingService {
/**
* Returns the next objective ID for the given NeighborSet.
* If the nextObjective does not exist, a new one is created and
- * it's id is returned.
- * TODO move the side-effect creation of a Next Objective into a new method
+ * its id is returned.
*
* @param deviceId Device ID
* @param ns NegighborSet
@@ -441,18 +451,19 @@ public class SegmentRoutingManager implements SegmentRoutingService {
return groupHandlerMap
.get(deviceId).getNextObjectiveId(ns, meta);
} else {
- log.warn("getNextObjectiveId query in device {} not found", deviceId);
+ log.warn("getNextObjectiveId query - groupHandler for device {} "
+ + "not found", deviceId);
return -1;
}
}
/**
- * Returns the next objective ID for the Subnet given. If the nextObjectiveID does not exist,
- * a new one is created and returned.
+ * Returns the next objective ID for the given subnet prefix. It is expected
+ * that the next-objective has been pre-created from configuration.
*
* @param deviceId Device ID
* @param prefix Subnet
- * @return next objective ID
+ * @return next objective ID or -1 if it was not found
*/
public int getSubnetNextObjectiveId(DeviceId deviceId, IpPrefix prefix) {
if (groupHandlerMap.get(deviceId) != null) {
@@ -460,7 +471,33 @@ public class SegmentRoutingManager implements SegmentRoutingService {
return groupHandlerMap
.get(deviceId).getSubnetNextObjectiveId(prefix);
} else {
- log.warn("getSubnetNextObjectiveId query in device {} not found", deviceId);
+ log.warn("getSubnetNextObjectiveId query - groupHandler for "
+ + "device {} not found", deviceId);
+ return -1;
+ }
+ }
+
+ /**
+ * Returns the next objective ID for the given portNumber, 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, a new one is created and its id is returned.
+ *
+ * @param deviceId Device ID
+ * @param portNum port number on device for which NextObjective is queried
+ * @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
+ * @return next objective ID or -1 if it was not found
+ */
+ public int getPortNextObjectiveId(DeviceId deviceId, PortNumber portNum,
+ TrafficTreatment treatment,
+ TrafficSelector meta) {
+ DefaultGroupHandler ghdlr = groupHandlerMap.get(deviceId);
+ if (ghdlr != null) {
+ return ghdlr.getPortNextObjectiveId(portNum, treatment, meta);
+ } else {
+ log.warn("getPortNextObjectiveId query - groupHandler for device {}"
+ + " not found", deviceId);
return -1;
}
}
@@ -475,7 +512,7 @@ public class SegmentRoutingManager implements SegmentRoutingService {
InboundPacket pkt = context.inPacket();
Ethernet ethernet = pkt.parsed();
-
+ log.trace("Rcvd pktin: {}", ethernet);
if (ethernet.getEtherType() == Ethernet.TYPE_ARP) {
arpHandler.processPacketIn(pkt);
} else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
@@ -517,6 +554,7 @@ public class SegmentRoutingManager implements SegmentRoutingService {
}
}
+ @SuppressWarnings("rawtypes")
private void scheduleEventHandlerIfNotScheduled(Event event) {
synchronized (threadSchedulerLock) {
eventQueue.add(event);
@@ -539,6 +577,7 @@ public class SegmentRoutingManager implements SegmentRoutingService {
public void run() {
try {
while (true) {
+ @SuppressWarnings("rawtypes")
Event event = null;
synchronized (threadSchedulerLock) {
if (!eventQueue.isEmpty()) {
@@ -647,7 +686,8 @@ public class SegmentRoutingManager implements SegmentRoutingService {
linkService,
flowObjectiveService,
nsNextObjStore,
- subnetNextObjStore);
+ subnetNextObjStore,
+ portNextObjStore);
} catch (DeviceConfigNotFoundException e) {
log.warn(e.getMessage() + " Aborting processDeviceAdded.");
return;
@@ -658,6 +698,7 @@ public class SegmentRoutingManager implements SegmentRoutingService {
// port addressing rules to the driver as well irrespective of whether
// this instance is the master or not.
defaultRoutingHandler.populatePortAddressingRules(device.id());
+ hostListener.readInitialHosts();
}
if (mastershipService.isLocalMaster(device.id())) {
DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
@@ -713,7 +754,8 @@ public class SegmentRoutingManager implements SegmentRoutingService {
linkService,
flowObjectiveService,
nsNextObjStore,
- subnetNextObjStore);
+ subnetNextObjStore,
+ portNextObjStore);
} catch (DeviceConfigNotFoundException e) {
log.warn(e.getMessage() + " Aborting configureNetwork.");
return;
@@ -725,6 +767,7 @@ public class SegmentRoutingManager implements SegmentRoutingService {
// port addressing rules to the driver as well, irrespective of whether
// this instance is the master or not.
defaultRoutingHandler.populatePortAddressingRules(device.id());
+ hostListener.readInitialHosts();
}
if (mastershipService.isLocalMaster(device.id())) {
DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
@@ -751,22 +794,66 @@ public class SegmentRoutingManager implements SegmentRoutingService {
}
}
+ // TODO Move bridging table population to a separate class
private class InternalHostListener implements HostListener {
+ private void readInitialHosts() {
+ hostService.getHosts().forEach(host -> {
+ MacAddress mac = host.mac();
+ VlanId vlanId = host.vlan();
+ DeviceId deviceId = host.location().deviceId();
+ PortNumber port = host.location().port();
+ Set<IpAddress> ips = host.ipAddresses();
+ log.debug("Host {}/{} is added at {}:{}", mac, vlanId, deviceId, port);
+
+ // Populate bridging table entry
+ ForwardingObjective.Builder fob =
+ getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
+ flowObjectiveService.forward(deviceId, fob.add(
+ new BridgingTableObjectiveContext(mac, vlanId)
+ ));
+
+ // Populate IP table entry
+ ips.forEach(ip -> {
+ if (ip.isIp4()) {
+ routingRulePopulator.populateIpRuleForHost(
+ deviceId, ip.getIp4Address(), mac, port);
+ }
+ });
+ });
+ }
+
private ForwardingObjective.Builder getForwardingObjectiveBuilder(
- MacAddress mac, VlanId vlanId, PortNumber port) {
+ DeviceId deviceId, MacAddress mac, VlanId vlanId,
+ PortNumber outport) {
+ // match rule
TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
sbuilder.matchEthDst(mac);
sbuilder.matchVlanId(vlanId);
TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
- // TODO Move popVlan from flow action to group action
tbuilder.immediate().popVlan();
- tbuilder.immediate().setOutput(port);
+ tbuilder.immediate().setOutput(outport);
+
+ // for switch pipelines that need it, provide outgoing vlan as metadata
+ VlanId outvlan = null;
+ Ip4Prefix subnet = deviceConfiguration.getPortSubnet(deviceId, outport);
+ if (subnet == null) {
+ outvlan = VlanId.vlanId(ASSIGNED_VLAN_NO_SUBNET);
+ } else {
+ outvlan = getSubnetAssignedVlanId(deviceId, subnet);
+ }
+ TrafficSelector meta = DefaultTrafficSelector.builder()
+ .matchVlanId(outvlan).build();
+
+ // All forwarding is via Groups. Drivers can re-purpose to flow-actions if needed.
+ int portNextObjId = getPortNextObjectiveId(deviceId, outport,
+ tbuilder.build(),
+ meta);
return DefaultForwardingObjective.builder()
.withFlag(ForwardingObjective.Flag.SPECIFIC)
.withSelector(sbuilder.build())
- .withTreatment(tbuilder.build())
+ .nextStep(portNextObjId)
.withPriority(100)
.fromApp(appId)
.makePermanent();
@@ -778,12 +865,13 @@ public class SegmentRoutingManager implements SegmentRoutingService {
DeviceId deviceId = event.subject().location().deviceId();
PortNumber port = event.subject().location().port();
Set<IpAddress> ips = event.subject().ipAddresses();
- log.debug("Host {}/{} is added at {}:{}", mac, vlanId, deviceId, port);
+ log.info("Host {}/{} is added at {}:{}", mac, vlanId, deviceId, port);
- // TODO Move bridging table population to a separate class
// Populate bridging table entry
+ log.debug("Populate L2 table entry for host {} at {}:{}",
+ mac, deviceId, port);
ForwardingObjective.Builder fob =
- getForwardingObjectiveBuilder(mac, vlanId, port);
+ getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
flowObjectiveService.forward(deviceId, fob.add(
new BridgingTableObjectiveContext(mac, vlanId)
));
@@ -807,7 +895,7 @@ public class SegmentRoutingManager implements SegmentRoutingService {
// Revoke bridging table entry
ForwardingObjective.Builder fob =
- getForwardingObjectiveBuilder(mac, vlanId, port);
+ getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
flowObjectiveService.forward(deviceId, fob.remove(
new BridgingTableObjectiveContext(mac, vlanId)
));
@@ -835,7 +923,7 @@ public class SegmentRoutingManager implements SegmentRoutingService {
// Revoke previous bridging table entry
ForwardingObjective.Builder prevFob =
- getForwardingObjectiveBuilder(mac, vlanId, prevPort);
+ getForwardingObjectiveBuilder(prevDeviceId, mac, vlanId, prevPort);
flowObjectiveService.forward(prevDeviceId, prevFob.remove(
new BridgingTableObjectiveContext(mac, vlanId)
));
@@ -850,7 +938,7 @@ public class SegmentRoutingManager implements SegmentRoutingService {
// Populate new bridging table entry
ForwardingObjective.Builder newFob =
- getForwardingObjectiveBuilder(mac, vlanId, prevPort);
+ getForwardingObjectiveBuilder(newDeviceId, mac, vlanId, newPort);
flowObjectiveService.forward(newDeviceId, newFob.add(
new BridgingTableObjectiveContext(mac, vlanId)
));
diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/TunnelHandler.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/TunnelHandler.java
index b86adada..5a82e712 100644
--- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/TunnelHandler.java
+++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/TunnelHandler.java
@@ -158,7 +158,7 @@ public class TunnelHandler {
private int createGroupsForTunnel(Tunnel tunnel) {
- List<Integer> portNumbers;
+ Set<Integer> portNumbers;
final int groupError = -1;
DeviceId deviceId = config.getDeviceId(tunnel.labelIds().get(0));
diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/config/DeviceConfiguration.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/config/DeviceConfiguration.java
index 0ad00679..dbac596d 100644
--- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/config/DeviceConfiguration.java
+++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/config/DeviceConfiguration.java
@@ -16,7 +16,6 @@
package org.onosproject.segmentrouting.config;
import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Lists;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;
import org.onlab.packet.MacAddress;
@@ -26,7 +25,6 @@ import org.onosproject.incubator.net.intf.Interface;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.config.NetworkConfigRegistry;
import org.onosproject.net.host.InterfaceIpAddress;
-import org.onosproject.segmentrouting.config.SegmentRoutingConfig.AdjacencySid;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
import org.slf4j.Logger;
@@ -34,6 +32,7 @@ import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -60,7 +59,7 @@ public class DeviceConfiguration implements DeviceProperties {
boolean isEdge;
HashMap<PortNumber, Ip4Address> gatewayIps;
HashMap<PortNumber, Ip4Prefix> subnets;
- List<AdjacencySid> adjacencySids;
+ Map<Integer, Set<Integer>> adjacencySids;
public SegmentRouterInfo() {
this.gatewayIps = new HashMap<>();
@@ -83,11 +82,11 @@ public class DeviceConfiguration implements DeviceProperties {
cfgService.getConfig(subject, SegmentRoutingConfig.class);
SegmentRouterInfo info = new SegmentRouterInfo();
info.deviceId = subject;
- info.nodeSid = config.getSid();
- info.ip = config.getIp();
- info.mac = config.getMac();
+ info.nodeSid = config.nodeSid();
+ info.ip = config.routerIp();
+ info.mac = config.routerMac();
info.isEdge = config.isEdgeRouter();
- info.adjacencySids = config.getAdjacencySids();
+ info.adjacencySids = config.adjacencySids();
this.deviceConfigMap.put(info.deviceId, info);
this.allSegmentIds.add(info.nodeSid);
@@ -410,19 +409,13 @@ public class DeviceConfiguration implements DeviceProperties {
*
* @param deviceId device identification of the router
* @param sid adjacency Sid
- * @return list of port numbers
+ * @return set of port numbers
*/
- public List<Integer> getPortsForAdjacencySid(DeviceId deviceId, int sid) {
+ public Set<Integer> getPortsForAdjacencySid(DeviceId deviceId, int sid) {
SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
- if (srinfo != null) {
- for (AdjacencySid asid : srinfo.adjacencySids) {
- if (asid.getAsid() == sid) {
- return asid.getPorts();
- }
- }
- }
-
- return Lists.newArrayList();
+ return srinfo != null ?
+ ImmutableSet.copyOf(srinfo.adjacencySids.get(sid)) :
+ ImmutableSet.copyOf(new HashSet<>());
}
/**
@@ -435,20 +428,6 @@ public class DeviceConfiguration implements DeviceProperties {
*/
public boolean isAdjacencySid(DeviceId deviceId, int sid) {
SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
- if (srinfo != null) {
- if (srinfo.adjacencySids.isEmpty()) {
- return false;
- } else {
- for (AdjacencySid asid:
- srinfo.adjacencySids) {
- if (asid.getAsid() == sid) {
- return true;
- }
- }
- return false;
- }
- }
-
- return false;
+ return srinfo != null && srinfo.adjacencySids.containsKey(sid);
}
} \ No newline at end of file
diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/config/SegmentRoutingConfig.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/config/SegmentRoutingConfig.java
index 6dc3f0db..f788925c 100644
--- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/config/SegmentRoutingConfig.java
+++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/config/SegmentRoutingConfig.java
@@ -16,113 +16,210 @@
package org.onosproject.segmentrouting.config;
+import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.ImmutableMap;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.MacAddress;
import org.onosproject.net.DeviceId;
import org.onosproject.net.config.Config;
-import org.onosproject.net.config.basics.BasicElementConfig;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
import java.util.Optional;
+import java.util.Set;
/**
* Configuration object for Segment Routing Application.
*/
public class SegmentRoutingConfig extends Config<DeviceId> {
- private static final String NAME = "name";
- private static final String IP = "routerIp";
- private static final String MAC = "routerMac";
- private static final String SID = "nodeSid";
- private static final String EDGE = "isEdgeRouter";
- private static final String ADJSID = "adjacencySids";
-
- public Optional<String> getName() {
+ public static final String NAME = "name";
+ public static final String IP = "routerIp";
+ public static final String MAC = "routerMac";
+ public static final String SID = "nodeSid";
+ public static final String EDGE = "isEdgeRouter";
+ public static final String ADJSIDS = "adjacencySids";
+ public static final String ADJSID = "adjSid";
+ public static final String PORTS = "ports";
+
+ @Override
+ public boolean isValid() {
+ return hasOnlyFields(NAME, IP, MAC, SID, EDGE, ADJSIDS, ADJSID, PORTS) &&
+ this.name() != null &&
+ this.routerIp() != null &&
+ this.routerMac() != null &&
+ this.nodeSid() != -1 &&
+ this.isEdgeRouter() != null &&
+ this.adjacencySids() != null;
+ }
+
+ /**
+ * Gets the name of the router.
+ *
+ * @return Optional name of the router. May be empty if not configured.
+ */
+ public Optional<String> name() {
String name = get(NAME, null);
return name != null ? Optional.of(name) : Optional.empty();
}
- public BasicElementConfig setName(String name) {
- return (BasicElementConfig) setOrClear(NAME, name);
+ /**
+ * Sets the name of the router.
+ *
+ * @param name name of the router.
+ * @return the config of the router.
+ */
+ public SegmentRoutingConfig setName(String name) {
+ return (SegmentRoutingConfig) setOrClear(NAME, name);
}
- public Ip4Address getIp() {
+ /**
+ * Gets the IP address of the router.
+ *
+ * @return IP address of the router. Or null if not configured.
+ */
+ public Ip4Address routerIp() {
String ip = get(IP, null);
return ip != null ? Ip4Address.valueOf(ip) : null;
}
- public BasicElementConfig setIp(String ip) {
- return (BasicElementConfig) setOrClear(IP, ip);
+ /**
+ * Sets the IP address of the router.
+ *
+ * @param ip IP address of the router.
+ * @return the config of the router.
+ */
+ public SegmentRoutingConfig setRouterIp(String ip) {
+ return (SegmentRoutingConfig) setOrClear(IP, ip);
}
- public MacAddress getMac() {
+ /**
+ * Gets the MAC address of the router.
+ *
+ * @return MAC address of the router. Or null if not configured.
+ */
+ public MacAddress routerMac() {
String mac = get(MAC, null);
return mac != null ? MacAddress.valueOf(mac) : null;
}
- public BasicElementConfig setMac(String mac) {
- return (BasicElementConfig) setOrClear(MAC, mac);
+ /**
+ * Sets the MAC address of the router.
+ *
+ * @param mac MAC address of the router.
+ * @return the config of the router.
+ */
+ public SegmentRoutingConfig setRouterMac(String mac) {
+ return (SegmentRoutingConfig) setOrClear(MAC, mac);
}
- public int getSid() {
+ /**
+ * Gets the node SID of the router.
+ *
+ * @return node SID of the router. Or -1 if not configured.
+ */
+ public int nodeSid() {
return get(SID, -1);
}
- public BasicElementConfig setSid(int sid) {
- return (BasicElementConfig) setOrClear(SID, sid);
+ /**
+ * Sets the node SID of the router.
+ *
+ * @param sid node SID of the router.
+ * @return the config of the router.
+ */
+ public SegmentRoutingConfig setNodeSid(int sid) {
+ return (SegmentRoutingConfig) setOrClear(SID, sid);
}
- public boolean isEdgeRouter() {
- return get(EDGE, false);
+ /**
+ * Checks if the router is an edge router.
+ *
+ * @return true if the router is an edge router.
+ * false if the router is not an edge router.
+ * null if the value is not configured.
+ */
+ public Boolean isEdgeRouter() {
+ String isEdgeRouter = get(EDGE, null);
+ return isEdgeRouter != null ?
+ Boolean.valueOf(isEdgeRouter) :
+ null;
}
- public BasicElementConfig setEdgeRouter(boolean isEdgeRouter) {
- return (BasicElementConfig) setOrClear(EDGE, isEdgeRouter);
+ /**
+ * Specifies if the router is an edge router.
+ *
+ * @param isEdgeRouter true if the router is an edge router.
+ * @return the config of the router.
+ */
+ public SegmentRoutingConfig setIsEdgeRouter(boolean isEdgeRouter) {
+ return (SegmentRoutingConfig) setOrClear(EDGE, isEdgeRouter);
}
- public List<AdjacencySid> getAdjacencySids() {
- ArrayList<AdjacencySid> adjacencySids = new ArrayList<>();
-
- if (!object.has(ADJSID)) {
- return adjacencySids;
+ /**
+ * Gets the adjacency SIDs of the router.
+ *
+ * @return adjacency SIDs of the router. Or null if not configured.
+ */
+ public Map<Integer, Set<Integer>> adjacencySids() {
+ if (!object.has(ADJSIDS)) {
+ return null;
}
- ArrayNode adjacencySidNodes = (ArrayNode) object.path(ADJSID);
- adjacencySidNodes.forEach(adjacencySidNode -> {
- int asid = adjacencySidNode.path(AdjacencySid.ASID).asInt();
-
- ArrayList<Integer> ports = new ArrayList<Integer>();
- ArrayNode portsNodes = (ArrayNode) adjacencySidNode.path(AdjacencySid.PORTS);
- portsNodes.forEach(portNode -> {
- ports.add(portNode.asInt());
- });
-
- AdjacencySid adjacencySid = new AdjacencySid(asid, ports);
- adjacencySids.add(adjacencySid);
- });
+ Map<Integer, Set<Integer>> adjacencySids = new HashMap<>();
+ ArrayNode adjacencySidsNode = (ArrayNode) object.path(ADJSIDS);
+ for (JsonNode adjacencySidNode : adjacencySidsNode) {
+ int asid = adjacencySidNode.path(ADJSID).asInt(-1);
+ if (asid == -1) {
+ return null;
+ }
+
+ HashSet<Integer> ports = new HashSet<>();
+ ArrayNode portsNode = (ArrayNode) adjacencySidNode.path(PORTS);
+ for (JsonNode portNode : portsNode) {
+ int port = portNode.asInt(-1);
+ if (port == -1) {
+ return null;
+ }
+ ports.add(port);
+ }
+ adjacencySids.put(asid, ports);
+ }
- return adjacencySids;
+ return ImmutableMap.copyOf(adjacencySids);
}
- public class AdjacencySid {
- private static final String ASID = "adjSid";
- private static final String PORTS = "ports";
-
- int asid;
- List<Integer> ports;
-
- public AdjacencySid(int asid, List<Integer> ports) {
- this.asid = asid;
- this.ports = ports;
- }
+ /**
+ * Sets the adjacency SIDs of the router.
+ *
+ * @param adjacencySids adjacency SIDs of the router.
+ * @return the config of the router.
+ */
+ public SegmentRoutingConfig setAdjacencySids(Map<Integer, Set<Integer>> adjacencySids) {
+ if (adjacencySids == null) {
+ object.remove(ADJSIDS);
+ } else {
+ ArrayNode adjacencySidsNode = mapper.createArrayNode();
+
+ adjacencySids.forEach((sid, ports) -> {
+ ObjectNode adjacencySidNode = mapper.createObjectNode();
+
+ adjacencySidNode.put(ADJSID, sid);
+
+ ArrayNode portsNode = mapper.createArrayNode();
+ ports.forEach(port -> {
+ portsNode.add(port.toString());
+ });
+ adjacencySidNode.set(PORTS, portsNode);
+
+ adjacencySidsNode.add(adjacencySidNode);
+ });
- public int getAsid() {
- return asid;
+ object.set(ADJSIDS, adjacencySidsNode);
}
- public List<Integer> getPorts() {
- return ports;
- }
+ return this;
}
} \ No newline at end of file
diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultEdgeGroupHandler.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultEdgeGroupHandler.java
index 6b6d960a..32c53654 100644
--- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultEdgeGroupHandler.java
+++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultEdgeGroupHandler.java
@@ -56,9 +56,11 @@ public class DefaultEdgeGroupHandler extends DefaultGroupHandler {
NeighborSetNextObjectiveStoreKey,
Integer> nsNextObjStore,
EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
- Integer> subnetNextObjStore) {
+ Integer> subnetNextObjStore,
+ EventuallyConsistentMap<PortNextObjectiveStoreKey,
+ Integer> portNextObjStore) {
super(deviceId, appId, config, linkService, flowObjService,
- nsNextObjStore, subnetNextObjStore);
+ nsNextObjStore, subnetNextObjStore, portNextObjStore);
}
@Override
diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
index e792bf66..bc394b84 100644
--- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
+++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
@@ -80,6 +80,8 @@ public class DefaultGroupHandler {
NeighborSetNextObjectiveStoreKey, Integer> nsNextObjStore = null;
protected EventuallyConsistentMap<
SubnetNextObjectiveStoreKey, Integer> subnetNextObjStore = null;
+ protected EventuallyConsistentMap<
+ PortNextObjectiveStoreKey, Integer> portNextObjStore = null;
protected KryoNamespace.Builder kryo = new KryoNamespace.Builder()
.register(URI.class).register(HashSet.class)
@@ -93,11 +95,12 @@ public class DefaultGroupHandler {
DeviceProperties config,
LinkService linkService,
FlowObjectiveService flowObjService,
- EventuallyConsistentMap<
- NeighborSetNextObjectiveStoreKey,
+ EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey,
Integer> nsNextObjStore,
EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
- Integer> subnetNextObjStore) {
+ Integer> subnetNextObjStore,
+ EventuallyConsistentMap<PortNextObjectiveStoreKey,
+ Integer> portNextObjStore) {
this.deviceId = checkNotNull(deviceId);
this.appId = checkNotNull(appId);
this.deviceConfig = checkNotNull(config);
@@ -114,6 +117,7 @@ public class DefaultGroupHandler {
this.flowObjectiveService = flowObjService;
this.nsNextObjStore = nsNextObjStore;
this.subnetNextObjStore = subnetNextObjStore;
+ this.portNextObjStore = portNextObjStore;
populateNeighborMaps();
}
@@ -133,30 +137,34 @@ public class DefaultGroupHandler {
* @throws DeviceConfigNotFoundException if the device configuration is not found
* @return default group handler type
*/
- public static DefaultGroupHandler createGroupHandler(DeviceId deviceId,
- ApplicationId appId,
- DeviceProperties config,
- LinkService linkService,
- FlowObjectiveService flowObjService,
- EventuallyConsistentMap<
- NeighborSetNextObjectiveStoreKey,
- Integer> nsNextObjStore,
- EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
- Integer> subnetNextObjStore)
- throws DeviceConfigNotFoundException {
+ public static DefaultGroupHandler createGroupHandler(
+ DeviceId deviceId,
+ ApplicationId appId,
+ DeviceProperties config,
+ LinkService linkService,
+ FlowObjectiveService flowObjService,
+ EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey,
+ Integer> nsNextObjStore,
+ EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
+ Integer> subnetNextObjStore,
+ EventuallyConsistentMap<PortNextObjectiveStoreKey,
+ Integer> portNextObjStore)
+ throws DeviceConfigNotFoundException {
// handle possible exception in the caller
if (config.isEdgeDevice(deviceId)) {
return new DefaultEdgeGroupHandler(deviceId, appId, config,
linkService,
flowObjService,
nsNextObjStore,
- subnetNextObjStore);
+ subnetNextObjStore,
+ portNextObjStore);
} else {
return new DefaultTransitGroupHandler(deviceId, appId, config,
linkService,
flowObjService,
nsNextObjStore,
- subnetNextObjStore);
+ subnetNextObjStore,
+ portNextObjStore);
}
}
@@ -231,25 +239,21 @@ public class DefaultGroupHandler {
Integer nextId = nsNextObjStore.
get(new NeighborSetNextObjectiveStoreKey(deviceId, ns));
- if (nextId != null) {
+ if (nextId != null && isMaster) {
NextObjective.Builder nextObjBuilder = DefaultNextObjective
.builder().withId(nextId)
.withType(NextObjective.Type.HASHED).fromApp(appId);
nextObjBuilder.addTreatment(tBuilder.build());
-
log.info("**linkUp in device {}: Adding Bucket "
- + "with Port {} to next object id {} and amIMaster:{}",
+ + "with Port {} to next object id {}",
deviceId,
newLink.src().port(),
- nextId, isMaster);
-
- if (isMaster) {
- NextObjective nextObjective = nextObjBuilder.
- addToExisting(new SRNextObjectiveContext(deviceId));
- flowObjectiveService.next(deviceId, nextObjective);
- }
- } else {
+ nextId);
+ NextObjective nextObjective = nextObjBuilder.
+ addToExisting(new SRNextObjectiveContext(deviceId));
+ flowObjectiveService.next(deviceId, nextObjective);
+ } else if (isMaster) {
log.warn("linkUp in device {}, but global store has no record "
+ "for neighbor-set {}", deviceId, ns);
}
@@ -331,8 +335,8 @@ public class DefaultGroupHandler {
}
/**
- * Returns the next objective associated with the neighborset.
- * If there is no next objective for this neighborset, this API
+ * Returns the next objective of type hashed associated with the neighborset.
+ * If there is no next objective for this neighborset, this method
* would create a next objective and return. Optionally metadata can be
* passed in for the creation of the next objective.
*
@@ -372,9 +376,10 @@ public class DefaultGroupHandler {
}
/**
- * Returns the next objective associated with the subnet.
- * If there is no next objective for this subnet, this API
- * would create a next objective and return.
+ * Returns the next objective of type broadcast associated with the subnet,
+ * or -1 if no such objective exists. Note that this method does NOT create
+ * the next objective as a side-effect. It is expected that is objective is
+ * created at startup from network configuration.
*
* @param prefix subnet information
* @return int if found or -1
@@ -387,6 +392,38 @@ public class DefaultGroupHandler {
}
/**
+ * Returns the next objective of type simple associated with the port on the
+ * device, given the treatment. Different treatments to the same port result
+ * in different next objectives. If no such objective exists, this method
+ * creates one and returns the id. Optionally metadata can be passed in for
+ * the creation of the objective.
+ *
+ * @param portNum the port number 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
+ * @return int if found or created, -1 if there are errors during the
+ * creation of the next objective.
+ */
+ public int getPortNextObjectiveId(PortNumber portNum, TrafficTreatment treatment,
+ TrafficSelector meta) {
+ Integer nextId = portNextObjStore.
+ get(new PortNextObjectiveStoreKey(deviceId, portNum, treatment));
+ if (nextId == null) {
+ log.trace("getPortNextObjectiveId in device{}: Next objective id "
+ + "not found for {} and {} creating", deviceId, portNum);
+ createGroupFromPort(portNum, treatment, meta);
+ nextId = portNextObjStore.get(
+ new PortNextObjectiveStoreKey(deviceId, portNum, treatment));
+ if (nextId == null) {
+ log.warn("getPortNextObjectiveId: unable to create next obj"
+ + "for dev:{} port{}", deviceId, portNum);
+ return -1;
+ }
+ }
+ return nextId;
+ }
+
+ /**
* Checks if the next objective ID (group) for the neighbor set exists or not.
*
* @param ns neighbor set to check
@@ -561,7 +598,7 @@ public class DefaultGroupHandler {
}
}
if (meta != null) {
- nextObjBuilder.setMeta(meta);
+ nextObjBuilder.withMeta(meta);
}
NextObjective nextObj = nextObjBuilder.
add(new SRNextObjectiveContext(deviceId));
@@ -574,7 +611,10 @@ public class DefaultGroupHandler {
}
}
-
+ /**
+ * Creates broadcast groups for all ports in the same configured subnet.
+ *
+ */
public void createGroupsFromSubnetConfig() {
Map<Ip4Prefix, List<PortNumber>> subnetPortMap =
this.deviceConfig.getSubnetPortsMap(this.deviceId);
@@ -612,6 +652,37 @@ public class DefaultGroupHandler {
});
}
+
+ /**
+ * Create simple next objective for a single port. The treatments can include
+ * all outgoing actions that need to happen on the packet.
+ *
+ * @param portNum the outgoing port on the device
+ * @param treatment the actions to apply on the packets (should include outport)
+ * @param meta optional data to pass to the driver
+ */
+ public void createGroupFromPort(PortNumber portNum, TrafficTreatment treatment,
+ TrafficSelector meta) {
+ int nextId = flowObjectiveService.allocateNextId();
+ PortNextObjectiveStoreKey key = new PortNextObjectiveStoreKey(
+ deviceId, portNum, treatment);
+
+ NextObjective.Builder nextObjBuilder = DefaultNextObjective
+ .builder().withId(nextId)
+ .withType(NextObjective.Type.SIMPLE)
+ .addTreatment(treatment)
+ .fromApp(appId)
+ .withMeta(meta);
+
+ NextObjective nextObj = nextObjBuilder.add();
+ flowObjectiveService.next(deviceId, nextObj);
+ log.debug("createGroupFromPort: Submited next objective {} in device {} "
+ + "for port {}", nextId, deviceId, portNum);
+
+ portNextObjStore.put(key, nextId);
+ }
+
+
public GroupKey getGroupKey(Object obj) {
return new DefaultGroupKey(kryo.build().serialize(obj));
}
diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultTransitGroupHandler.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultTransitGroupHandler.java
index 14d77ba6..7a43e73d 100644
--- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultTransitGroupHandler.java
+++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultTransitGroupHandler.java
@@ -50,9 +50,11 @@ public class DefaultTransitGroupHandler extends DefaultGroupHandler {
NeighborSetNextObjectiveStoreKey,
Integer> nsNextObjStore,
EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
- Integer> subnetNextObjStore) {
+ Integer> subnetNextObjStore,
+ EventuallyConsistentMap<PortNextObjectiveStoreKey,
+ Integer> portNextObjStore) {
super(deviceId, appId, config, linkService, flowObjService,
- nsNextObjStore, subnetNextObjStore);
+ nsNextObjStore, subnetNextObjStore, portNextObjStore);
}
@Override
diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupHandler.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupHandler.java
index 55142078..ef143dc7 100644
--- a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupHandler.java
+++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupHandler.java
@@ -68,9 +68,11 @@ public class PolicyGroupHandler extends DefaultGroupHandler {
EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey,
Integer> nsNextObjStore,
EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
- Integer> subnetNextObjStore) {
+ Integer> subnetNextObjStore,
+ EventuallyConsistentMap<PortNextObjectiveStoreKey,
+ Integer> portNextObjStore) {
super(deviceId, appId, config, linkService, flowObjService,
- nsNextObjStore, subnetNextObjStore);
+ nsNextObjStore, subnetNextObjStore, portNextObjStore);
}
public PolicyGroupIdentifier createPolicyGroupChain(String id,
diff --git a/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PortNextObjectiveStoreKey.java b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PortNextObjectiveStoreKey.java
new file mode 100644
index 00000000..5555565c
--- /dev/null
+++ b/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PortNextObjectiveStoreKey.java
@@ -0,0 +1,77 @@
+package org.onosproject.segmentrouting.grouphandler;
+
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.TrafficTreatment;
+
+import java.util.Objects;
+
+/**
+ * Class definition of Key for Device/Port to NextObjective store. Since there
+ * can be multiple next objectives to the same physical port, we differentiate
+ * between them by including the treatment in the key.
+ */
+public class PortNextObjectiveStoreKey {
+ private final DeviceId deviceId;
+ private final PortNumber portNum;
+ private final TrafficTreatment treatment;
+
+ public PortNextObjectiveStoreKey(DeviceId deviceId, PortNumber portNum,
+ TrafficTreatment treatment) {
+ this.deviceId = deviceId;
+ this.portNum = portNum;
+ this.treatment = treatment;
+ }
+
+ /**
+ * Gets device id in this PortNextObjectiveStoreKey.
+ *
+ * @return device id
+ */
+ public DeviceId deviceId() {
+ return deviceId;
+ }
+
+ /**
+ * Gets port information in this PortNextObjectiveStoreKey.
+ *
+ * @return port information
+ */
+ public PortNumber portNumber() {
+ return portNum;
+ }
+
+ /**
+ * Gets treatment information in this PortNextObjectiveStoreKey.
+ *
+ * @return treatment information
+ */
+ public TrafficTreatment treatment() {
+ return treatment;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof PortNextObjectiveStoreKey)) {
+ return false;
+ }
+ PortNextObjectiveStoreKey that =
+ (PortNextObjectiveStoreKey) o;
+ return (Objects.equals(this.deviceId, that.deviceId) &&
+ Objects.equals(this.portNum, that.portNum) &&
+ Objects.equals(this.treatment, that.treatment));
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(deviceId, portNum, treatment);
+ }
+
+ @Override
+ public String toString() {
+ return "Device: " + deviceId + " Port: " + portNum + " Treatment: " + treatment;
+ }
+}