Route reprogamming using group substitution during next hop movement

Change-Id: Idf8362dac522722ca67747e245bfd836e6ee6292
This commit is contained in:
Ruchi Sahota 2019-01-28 01:08:18 +00:00 committed by Charles Chan
parent a3ce00ba00
commit ef0761c211
19 changed files with 762 additions and 52 deletions

View File

@ -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);
}
}

View File

@ -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);
}
});
}));

View File

@ -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()));
}
});
});

View File

@ -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());

View File

@ -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()));

View File

@ -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.
*

View File

@ -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());
}
}

View File

@ -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.
*

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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);

View File

@ -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);
}
}
}

View File

@ -595,4 +595,4 @@ public class RouteHandlerTest {
verify(srManager.deviceConfiguration);
}
}
}

View File

@ -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

View File

@ -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:

View File

@ -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 -->

View File

@ -109,6 +109,7 @@ CLI_COMMANDS=(
"sr-next-vlan"
"sr-next-pw"
"sr-next-xconnect"
"sr-next-mac-vlan"
"dhcp-relay"
"mcast-host-routes"