use of org.onosproject.net.HostLocation in project onos by opennetworkinglab.
the class Dhcp6HandlerImpl method addHostOrRoute.
/**
* add host or route and update dhcp relay record.
*
* @param directConnFlag flag to show that packet is from directly connected client
* @param location client side connect point
* @param dhcp6Relay the dhcp6 payload
* @param embeddedDhcp6 the dhcp6 payload within relay
* @param srcMac client gw/host macAddress
* @param clientInterface client interface
* @param vlanIdInUse vlanid encoded in the interface id Option
*/
private void addHostOrRoute(boolean directConnFlag, ConnectPoint location, DHCP6 dhcp6Relay, DHCP6 embeddedDhcp6, MacAddress srcMac, Interface clientInterface, VlanId vlanIdInUse) {
log.debug("addHostOrRoute entered.");
VlanId vlanId;
if (clientInterface.vlanTagged().isEmpty()) {
vlanId = clientInterface.vlan();
} else {
// might be multiple vlan in same interface
vlanId = vlanIdInUse;
}
if (vlanId == null) {
vlanId = VlanId.NONE;
}
Boolean isMsgReply = Dhcp6HandlerUtil.isDhcp6Reply(dhcp6Relay);
MacAddress leafClientMac;
Byte leafMsgType;
Dhcp6ClientIdOption clientIdOption = Dhcp6HandlerUtil.extractClientId(directConnFlag, embeddedDhcp6);
if (clientIdOption != null) {
log.debug("CLIENTID option found {}", clientIdOption);
if ((clientIdOption.getDuid().getDuidType() == Dhcp6Duid.DuidType.DUID_LLT) || (clientIdOption.getDuid().getDuidType() == Dhcp6Duid.DuidType.DUID_LL)) {
leafClientMac = MacAddress.valueOf(clientIdOption.getDuid().getLinkLayerAddress());
} else {
log.warn("Link-Layer Address not supported in CLIENTID option. No DhcpRelay Record created.");
// dhcpRelayCountersStore.incrementCounter(gCount, DhcpRelayCounters.NO_LINKLOCAL_FAIL);
return;
}
} else {
log.warn("CLIENTID option NOT found. No DhcpRelay Record created.");
// dhcpRelayCountersStore.incrementCounter(gCount, DhcpRelayCounters.NO_CLIENTID_FAIL);
return;
}
HostId leafHostId = HostId.hostId(leafClientMac, vlanId);
DhcpRecord record = dhcpRelayStore.getDhcpRecord(leafHostId).orElse(null);
if (record == null) {
record = new DhcpRecord(HostId.hostId(leafClientMac, vlanId));
} else {
record = record.clone();
}
IpAddressInfo ipInfo;
PdPrefixInfo pdInfo = null;
if (directConnFlag) {
// Add to host store if it connect to network directly
ipInfo = extractIpAddress(embeddedDhcp6);
if (ipInfo != null) {
if (isMsgReply) {
Set<IpAddress> ips = Sets.newHashSet(ipInfo.ip6Address);
HostId hostId = HostId.hostId(srcMac, vlanId);
Host host = hostService.getHost(hostId);
HostLocation hostLocation = new HostLocation(clientInterface.connectPoint(), System.currentTimeMillis());
Set<HostLocation> hostLocations = Sets.newHashSet(hostLocation);
if (host != null) {
// Dual homing support:
// if host exists, use old locations and new location
hostLocations.addAll(host.locations());
}
HostDescription desc = new DefaultHostDescription(srcMac, vlanId, hostLocations, ips, false);
log.debug("adding Host for directly connected.");
log.debug("client mac {} client vlan {} hostlocation {}", HexString.toHexString(srcMac.toBytes(), ":"), vlanId, hostLocation.toString());
// Replace the ip when dhcp server give the host new ip address
providerService.hostDetected(hostId, desc, false);
}
} else {
log.warn("ipAddress not found. Do not add Host {} for directly connected.", HostId.hostId(srcMac, vlanId).toString());
}
leafMsgType = embeddedDhcp6.getMsgType();
} else {
// Add to route store if it does not connect to network directly
// pick out the first link-local ip address
IpAddress nextHopIp = getFirstIpByHost(directConnFlag, srcMac, vlanId);
if (nextHopIp == null) {
log.warn("Can't find link-local IP address of gateway mac {} vlanId {}", srcMac, vlanId);
// dhcpRelayCountersStore.incrementCounter(gCount, DhcpRelayCounters.NO_LINKLOCAL_GW);
return;
}
DHCP6 leafDhcp = Dhcp6HandlerUtil.getDhcp6Leaf(embeddedDhcp6);
ipInfo = extractIpAddress(leafDhcp);
if (ipInfo == null) {
log.debug("ip is null");
} else {
if (isMsgReply) {
Route routeForIP = new Route(Route.Source.DHCP, ipInfo.ip6Address.toIpPrefix(), nextHopIp);
log.debug("adding Route of 128 address for indirectly connected.");
routeStore.replaceRoute(routeForIP);
}
}
pdInfo = extractPrefix(leafDhcp);
if (pdInfo == null) {
log.debug("ipPrefix is null ");
} else {
if (isMsgReply) {
Route routeForPrefix = new Route(Route.Source.DHCP, pdInfo.pdPrefix, nextHopIp);
log.debug("adding Route of PD for indirectly connected.");
routeStore.replaceRoute(routeForPrefix);
if (this.dhcpFpmEnabled) {
FpmRecord fpmRecord = new FpmRecord(pdInfo.pdPrefix, nextHopIp, FpmRecord.Type.DHCP_RELAY);
dhcpFpmPrefixStore.addFpmRecord(pdInfo.pdPrefix, fpmRecord);
}
}
}
leafMsgType = leafDhcp.getMsgType();
}
if (leafMsgType == DHCP6.MsgType.RELEASE.value() || (leafMsgType == DHCP6.MsgType.REPLY.value()) && ipInfo == null) {
log.warn("DHCP6 RELEASE/REPLY(null ip) from Server. MsgType {}", leafMsgType);
// return;
}
record.addLocation(new HostLocation(location, System.currentTimeMillis()));
if (leafMsgType == DHCP6.MsgType.REPLY.value()) {
if (ipInfo != null) {
log.debug("IP6 address is being stored into dhcp-relay store.");
log.debug("Client IP6 address {}", HexString.toHexString(ipInfo.ip6Address.toOctets(), ":"));
record.ip6Address(ipInfo.ip6Address);
record.updateAddrPrefTime(ipInfo.prefTime);
record.updateLastIp6Update();
} else {
log.debug("IP6 address is not returned from server. Maybe only PD is returned.");
}
if (pdInfo != null) {
log.debug("IP6 PD address {}", HexString.toHexString(pdInfo.pdPrefix.address().toOctets(), ":"));
record.pdPrefix(pdInfo.pdPrefix);
record.updatePdPrefTime(pdInfo.prefTime);
record.updateLastPdUpdate();
} else {
log.debug("IP6 PD address is not returned from server. Maybe only IPAddress is returned.");
}
}
record.getV6Counters().incrementCounter(Dhcp6HandlerUtil.getMsgTypeStr(leafMsgType));
record.ip6Status(DHCP6.MsgType.getType(leafMsgType));
record.setDirectlyConnected(directConnFlag);
record.updateLastSeen();
dhcpRelayStore.updateDhcpRecord(leafHostId, record);
/*
// TODO Use AtomicInteger for the counters
try {
recordSemaphore.acquire();
try {
dhcpRelayCountersStore.incrementCounter(gCount, Dhcp6HandlerUtil.getMsgTypeStr(leafMsgType));
} finally {
// calling release() after a successful acquire()
recordSemaphore.release();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
*/
}
use of org.onosproject.net.HostLocation in project onos by opennetworkinglab.
the class DhcpRelayManagerTest method testDhcp6DualHome.
@Test
public void testDhcp6DualHome() {
PacketContext packetContext = new TestDhcp6ReplyPacketContext(DHCP6.MsgType.REPLY.value(), CLIENT_DH_CP, CLIENT_MAC, CLIENT_VLAN, INTERFACE_IP_V6.ipAddress().getIp6Address(), 0, false, CLIENT_VLAN);
reset(manager.hostService);
expect(manager.hostService.getHostsByIp(CLIENT_LL_IP_V6)).andReturn(ImmutableSet.of(EXISTS_HOST)).anyTimes();
// FIXME: currently DHCPv6 has a bug, we can't get correct vlan of client......
// XXX: The vlan relied from DHCP6 handler might be wrong, do hack here
HostId hostId = HostId.hostId(CLIENT_MAC, VlanId.NONE);
expect(manager.hostService.getHost(hostId)).andReturn(EXISTS_HOST).anyTimes();
// XXX: sometimes this will work, sometimes not
expect(manager.hostService.getHost(CLIENT_HOST_ID)).andReturn(EXISTS_HOST).anyTimes();
Capture<HostDescription> capturedHostDesc = newCapture();
// XXX: also a hack here
mockHostProviderService.hostDetected(eq(hostId), capture(capturedHostDesc), eq(false));
expectLastCall().anyTimes();
mockHostProviderService.hostDetected(eq(CLIENT_HOST_ID), capture(capturedHostDesc), eq(false));
expectLastCall().anyTimes();
replay(mockHostProviderService, manager.hostService);
packetService.processPacket(packetContext);
assertAfter(PKT_PROCESSING_MS, () -> verify(mockHostProviderService));
assertAfter(PKT_PROCESSING_MS, () -> assertTrue(capturedHostDesc.hasCaptured()));
HostDescription hostDesc = capturedHostDesc.getValue();
Set<HostLocation> hostLocations = hostDesc.locations();
assertAfter(PKT_PROCESSING_MS, () -> assertEquals(2, hostLocations.size()));
assertAfter(PKT_PROCESSING_MS, () -> assertTrue(hostLocations.contains(CLIENT_LOCATION)));
assertAfter(PKT_PROCESSING_MS, () -> assertTrue(hostLocations.contains(CLIENT_DH_LOCATION)));
}
use of org.onosproject.net.HostLocation in project trellis-control by opennetworkinglab.
the class HostHandler method processHostMovedEventInternal.
private void processHostMovedEventInternal(HostEvent event) {
// This method will be called when one of the following value has changed:
// (1) locations (2) auxLocations or (3) both locations and auxLocations.
// We only need to proceed when effectiveLocation has changed.
Set<HostLocation> newLocations = effectiveLocations(event.subject());
Set<HostLocation> prevLocations = effectiveLocations(event.prevSubject());
if (newLocations.equals(prevLocations)) {
log.info("effectiveLocations of {} has not changed. Skipping {}", event.subject().id(), event);
return;
}
Host host = event.subject();
Host prevHost = event.prevSubject();
MacAddress hostMac = host.mac();
VlanId hostVlanId = host.vlan();
Set<IpAddress> prevIps = prevHost.ipAddresses();
Set<IpAddress> newIps = host.ipAddresses();
EthType hostTpid = host.tpid();
boolean doubleTaggedHost = isDoubleTaggedHost(host);
log.info("Host {}/{} is moved from {} to {}", hostMac, hostVlanId, prevLocations, newLocations);
Set<DeviceId> newDeviceIds = newLocations.stream().map(HostLocation::deviceId).collect(Collectors.toSet());
// For each old location
Sets.difference(prevLocations, newLocations).forEach(prevLocation -> {
// Remove routing rules for old IPs
Sets.difference(prevIps, newIps).forEach(ip -> {
if (doubleTaggedHost) {
processDoubleTaggedRoutingRule(prevLocation.deviceId(), prevLocation.port(), hostMac, host.innerVlan(), hostVlanId, hostTpid, ip, true);
} else {
processRoutingRule(prevLocation.deviceId(), prevLocation.port(), hostMac, hostVlanId, ip, true);
}
});
// Redirect the flows to pair link if configured
// Note: Do not continue removing any rule
Optional<DeviceId> pairDeviceId = srManager.getPairDeviceId(prevLocation.deviceId());
Optional<PortNumber> pairLocalPort = srManager.getPairLocalPort(prevLocation.deviceId());
if (pairDeviceId.isPresent() && pairLocalPort.isPresent() && newLocations.stream().anyMatch(location -> location.deviceId().equals(pairDeviceId.get())) && newLocations.stream().noneMatch(location -> location.deviceId().equals(prevLocation.deviceId()))) {
// NOTE: Since the pairLocalPort is trunk port, use assigned vlan of original port
// when the host is untagged
VlanId vlanId = Optional.ofNullable(srManager.getInternalVlanId(prevLocation)).orElse(hostVlanId);
processBridgingRule(prevLocation.deviceId(), pairLocalPort.get(), hostMac, vlanId, false);
newIps.forEach(ip -> processRoutingRule(prevLocation.deviceId(), pairLocalPort.get(), hostMac, vlanId, ip, false));
return;
}
// Otherwise, do not remove and let the adding part update the old flow
if (!newDeviceIds.contains(prevLocation.deviceId())) {
processBridgingRule(prevLocation.deviceId(), prevLocation.port(), hostMac, hostVlanId, true);
Sets.intersection(prevIps, newIps).forEach(ip -> {
if (doubleTaggedHost) {
processDoubleTaggedRoutingRule(prevLocation.deviceId(), prevLocation.port(), hostMac, host.innerVlan(), hostVlanId, hostTpid, ip, true);
} else {
processRoutingRule(prevLocation.deviceId(), prevLocation.port(), hostMac, hostVlanId, ip, true);
}
});
}
// Otherwise, do not remove and let the adding part update the old flow
if (newLocations.stream().noneMatch(newLocation -> {
VlanId oldAssignedVlan = srManager.getInternalVlanId(prevLocation);
VlanId newAssignedVlan = srManager.getInternalVlanId(newLocation);
// Host is tagged and the new location has the host vlan in vlan-tagged
return srManager.interfaceService.getTaggedVlanId(newLocation).contains(hostVlanId) || (oldAssignedVlan != null && newAssignedVlan != null && // Host is untagged and the new location has the same assigned vlan
oldAssignedVlan.equals(newAssignedVlan));
})) {
processBridgingRule(prevLocation.deviceId(), prevLocation.port(), hostMac, hostVlanId, true);
}
// Remove routing rules for unchanged IPs if none of the subnet of new location contains
// the IP. Otherwise, do not remove and let the adding part update the old flow
Sets.intersection(prevIps, newIps).forEach(ip -> {
if (newLocations.stream().noneMatch(newLocation -> srManager.deviceConfiguration.inSameSubnet(newLocation, ip))) {
if (doubleTaggedHost) {
processDoubleTaggedRoutingRule(prevLocation.deviceId(), prevLocation.port(), hostMac, host.innerVlan(), hostVlanId, hostTpid, ip, true);
} else {
processRoutingRule(prevLocation.deviceId(), prevLocation.port(), hostMac, hostVlanId, ip, true);
}
}
});
});
// For each new location, add all new IPs.
Sets.difference(newLocations, prevLocations).forEach(newLocation -> {
processBridgingRule(newLocation.deviceId(), newLocation.port(), hostMac, hostVlanId, false);
newIps.forEach(ip -> {
if (doubleTaggedHost) {
processDoubleTaggedRoutingRule(newLocation.deviceId(), newLocation.port(), hostMac, host.innerVlan(), hostVlanId, hostTpid, ip, false);
} else {
processRoutingRule(newLocation.deviceId(), newLocation.port(), hostMac, hostVlanId, ip, false);
}
});
// But will also cover [1A/x] -> [1A/y] -> [1A/y, 1B/y]
if (srManager.activeProbing) {
srManager.getPairDeviceId(newLocation.deviceId()).ifPresent(pairDeviceId -> srManager.getPairLocalPort(pairDeviceId).ifPresent(pairRemotePort -> probe(host, newLocation, pairDeviceId, pairRemotePort)));
}
});
// For each unchanged location, add new IPs and remove old IPs.
Sets.intersection(newLocations, prevLocations).forEach(unchangedLocation -> {
Sets.difference(prevIps, newIps).forEach(ip -> {
if (doubleTaggedHost) {
processDoubleTaggedRoutingRule(unchangedLocation.deviceId(), unchangedLocation.port(), hostMac, host.innerVlan(), hostVlanId, hostTpid, ip, true);
} else {
processRoutingRule(unchangedLocation.deviceId(), unchangedLocation.port(), hostMac, hostVlanId, ip, true);
}
});
Sets.difference(newIps, prevIps).forEach(ip -> {
if (doubleTaggedHost) {
processDoubleTaggedRoutingRule(unchangedLocation.deviceId(), unchangedLocation.port(), hostMac, host.innerVlan(), hostVlanId, hostTpid, ip, false);
} else {
processRoutingRule(unchangedLocation.deviceId(), unchangedLocation.port(), hostMac, hostVlanId, ip, false);
}
});
// Verify existing location and see if it is still valid
srManager.probingService.probeHost(host, unchangedLocation, ProbeMode.VERIFY);
});
// ensure dual-homed host locations have viable uplinks
if (newLocations.size() > prevLocations.size() || srManager.singleHomedDown) {
newLocations.forEach(loc -> {
if (srManager.shouldProgram(loc.deviceId())) {
srManager.linkHandler.checkUplinksForHost(loc);
}
});
}
}
use of org.onosproject.net.HostLocation in project trellis-control by opennetworkinglab.
the class HostHandler method processHostUpdatedEventInternal.
private void processHostUpdatedEventInternal(HostEvent event) {
Host host = event.subject();
MacAddress hostMac = host.mac();
VlanId hostVlanId = host.vlan();
EthType hostTpid = host.tpid();
Set<HostLocation> locations = effectiveLocations(host);
Set<IpAddress> prevIps = event.prevSubject().ipAddresses();
Set<IpAddress> newIps = host.ipAddresses();
log.info("Host {}/{} is updated", hostMac, hostVlanId);
locations.forEach(location -> {
Sets.difference(prevIps, newIps).forEach(ip -> {
if (isDoubleTaggedHost(host)) {
processDoubleTaggedRoutingRule(location.deviceId(), location.port(), hostMac, host.innerVlan(), hostVlanId, hostTpid, ip, true);
} else {
processRoutingRule(location.deviceId(), location.port(), hostMac, hostVlanId, ip, true);
}
});
Sets.difference(newIps, prevIps).forEach(ip -> {
if (isDoubleTaggedHost(host)) {
processDoubleTaggedRoutingRule(location.deviceId(), location.port(), hostMac, host.innerVlan(), hostVlanId, hostTpid, ip, false);
} else {
processRoutingRule(location.deviceId(), location.port(), hostMac, hostVlanId, ip, false);
}
});
});
// Use the pair link temporarily before the second location of a dual-homed host shows up.
// This do not affect single-homed hosts since the flow will be blocked in
// processBridgingRule or processRoutingRule due to VLAN or IP mismatch respectively
locations.forEach(location -> srManager.getPairDeviceId(location.deviceId()).ifPresent(pairDeviceId -> {
if (locations.stream().noneMatch(l -> l.deviceId().equals(pairDeviceId))) {
Set<IpAddress> ipsToAdd = Sets.difference(newIps, prevIps);
Set<IpAddress> ipsToRemove = Sets.difference(prevIps, newIps);
srManager.getPairLocalPort(pairDeviceId).ifPresent(pairRemotePort -> {
// NOTE: Since the pairLocalPort is trunk port, use assigned vlan of original port
// when the host is untagged
VlanId vlanId = vlanForPairPort(hostVlanId, location);
if (vlanId == null) {
return;
}
ipsToRemove.forEach(ip -> processRoutingRule(pairDeviceId, pairRemotePort, hostMac, vlanId, ip, true));
ipsToAdd.forEach(ip -> processRoutingRule(pairDeviceId, pairRemotePort, hostMac, vlanId, ip, false));
if (srManager.activeProbing) {
probe(host, location, pairDeviceId, pairRemotePort);
}
});
}
}));
}
use of org.onosproject.net.HostLocation in project trellis-control by opennetworkinglab.
the class HostHandler method processHostAddedAtLocation.
List<CompletableFuture<Objective>> processHostAddedAtLocation(Host host, HostLocation location) {
checkArgument(effectiveLocations(host).contains(location), "{} is not a location of {}", location, host);
MacAddress hostMac = host.mac();
VlanId hostVlanId = host.vlan();
Set<HostLocation> locations = effectiveLocations(host);
Set<IpAddress> ips = host.ipAddresses();
log.info("Host {}/{} is added at {}", hostMac, hostVlanId, locations);
List<CompletableFuture<Objective>> objectiveFutures = Lists.newArrayList();
// TODO Phased recovery does not trace double tagged hosts
if (isDoubleTaggedHost(host)) {
ips.forEach(ip -> processDoubleTaggedRoutingRule(location.deviceId(), location.port(), hostMac, host.innerVlan(), hostVlanId, host.tpid(), ip, false));
} else {
objectiveFutures.add(processBridgingRule(location.deviceId(), location.port(), hostMac, hostVlanId, false));
ips.forEach(ip -> objectiveFutures.add(processRoutingRule(location.deviceId(), location.port(), hostMac, hostVlanId, ip, false)));
}
// Use the pair link temporarily before the second location of a dual-homed host shows up.
// This do not affect single-homed hosts since the flow will be blocked in
// processBridgingRule or processRoutingRule due to VLAN or IP mismatch respectively
srManager.getPairDeviceId(location.deviceId()).ifPresent(pairDeviceId -> {
if (effectiveLocations(host).stream().noneMatch(l -> l.deviceId().equals(pairDeviceId))) {
srManager.getPairLocalPort(pairDeviceId).ifPresent(pairRemotePort -> {
// NOTE: Since the pairLocalPort is trunk port, use assigned vlan of original port
// when the host is untagged
VlanId vlanId = vlanForPairPort(hostVlanId, location);
if (vlanId == null) {
return;
}
objectiveFutures.add(processBridgingRule(pairDeviceId, pairRemotePort, hostMac, vlanId, false));
ips.forEach(ip -> objectiveFutures.add(processRoutingRule(pairDeviceId, pairRemotePort, hostMac, vlanId, ip, false)));
if (srManager.activeProbing) {
probe(host, location, pairDeviceId, pairRemotePort);
}
});
}
});
// NOTE: that we use the nexthop vlanId to retrieve the nextId
// while the vlanId used to program the L3 unicast chain
// is derived from the port configuration. In case of
// a tagged interface we use host vlanId. Host vlan should
// be part of the tags configured for that port. See the
// code in DefaultGroupHandler.updateL3UcastGroupBucket
int nextId = srManager.getMacVlanNextObjectiveId(location.deviceId(), hostMac, hostVlanId, null, false);
if (nextId != -1) {
log.debug(" Updating next objective for device {}, host {}/{}, port {}, nextid {}", location.deviceId(), hostMac, hostVlanId, location.port(), nextId);
srManager.updateMacVlanTreatment(location.deviceId(), hostMac, hostVlanId, location.port(), nextId);
}
log.debug("{} objectiveFutures for {}", objectiveFutures.size(), location);
return objectiveFutures;
}
Aggregations