use of org.onosproject.dhcprelay.store.DhcpRecord in project onos by opennetworkinglab.
the class Dhcp4HandlerImpl method processDhcpPacketFromServer.
/**
* Build the DHCP offer/ack with proper client port.
*
* @param ethernetPacket the original packet comes from server
* @return new packet which will send to the client
*/
private InternalPacket processDhcpPacketFromServer(PacketContext context, Ethernet ethernetPacket) {
// get dhcp header.
Ethernet etherReply = (Ethernet) ethernetPacket.clone();
IPv4 ipv4Packet = (IPv4) etherReply.getPayload();
UDP udpPacket = (UDP) ipv4Packet.getPayload();
DHCP dhcpPayload = (DHCP) udpPacket.getPayload();
// determine the vlanId of the client host - note that this vlan id
// could be different from the vlan in the packet from the server
Interface clientInterface = getClientInterface(ethernetPacket, dhcpPayload).orElse(null);
if (clientInterface == null) {
log.warn("Cannot find the interface for the DHCP {}", dhcpPayload);
return null;
}
VlanId vlanId;
ConnectPoint inPort = context.inPacket().receivedFrom();
boolean directConnFlag = directlyConnected(dhcpPayload);
DhcpServerInfo foundServerInfo = findServerInfoFromServer(directConnFlag, inPort);
if (foundServerInfo == null) {
log.warn("Cannot find server info for {} server, inPort {}", directConnFlag ? "direct" : "indirect", inPort);
return null;
} else {
if (Dhcp4HandlerUtil.isServerIpEmpty(foundServerInfo)) {
log.warn("Cannot find server info's ipaddress");
return null;
}
}
if (clientInterface.vlanTagged().isEmpty()) {
vlanId = clientInterface.vlan();
} else {
// might be multiple vlan in same interface
vlanId = getVlanIdFromRelayAgentOption(dhcpPayload);
}
if (vlanId == null) {
vlanId = VlanId.NONE;
}
etherReply.setVlanID(vlanId.toShort());
etherReply.setSourceMACAddress(clientInterface.mac());
if (!directlyConnected(dhcpPayload)) {
// if client is indirectly connected, try use next hop mac address
MacAddress macAddress = MacAddress.valueOf(dhcpPayload.getClientHardwareAddress());
HostId hostId = HostId.hostId(macAddress, vlanId);
if (((int) dhcpPayload.getFlags() & 0x8000) == 0x0000) {
DhcpRecord record = dhcpRelayStore.getDhcpRecord(hostId).orElse(null);
if (record != null) {
// if next hop can be found, use mac address of next hop
record.nextHop().ifPresent(etherReply::setDestinationMACAddress);
} else {
// otherwise, discard the packet
log.warn("Can't find record for host id {}, discard packet", hostId);
return null;
}
} else {
etherReply.setDestinationMACAddress(MacAddress.BROADCAST);
}
} else {
etherReply.setDestinationMACAddress(dhcpPayload.getClientHardwareAddress());
}
Ip4Address ipFacingClient = getFirstIpFromInterface(clientInterface);
if (directlyConnected(dhcpPayload)) {
// figure out the relay agent IP corresponding to the original request
if (ipFacingClient == null) {
log.warn("Cannot determine relay agent interface Ipv4 addr for host {}/{}. " + "Aborting relay for dhcp packet from server {}", etherReply.getDestinationMAC(), clientInterface.vlan(), ethernetPacket);
return null;
}
// SRC_IP: IP facing client
ipv4Packet.setSourceAddress(ipFacingClient.toInt());
} else {
// Get the IP address of the relay agent
Ip4Address relayAgentIp = foundServerInfo.getRelayAgentIp4(clientInterface.connectPoint().deviceId()).orElse(null);
if (relayAgentIp == null) {
if (ipFacingClient == null) {
log.warn("Cannot determine relay agent interface Ipv4 addr for host {}/{}. " + "Aborting relay for dhcp packet from server for indirect host {}", etherReply.getDestinationMAC(), clientInterface.vlan(), ethernetPacket);
return null;
} else {
// SRC_IP: IP facing client
ipv4Packet.setSourceAddress(ipFacingClient.toInt());
}
} else {
// SRC_IP: relay agent IP
ipv4Packet.setSourceAddress(relayAgentIp.toInt());
}
}
// DST_IP: offered IP
if (((int) dhcpPayload.getFlags() & 0x8000) == 0x0000) {
ipv4Packet.setDestinationAddress(dhcpPayload.getYourIPAddress());
} else {
ipv4Packet.setDestinationAddress(BROADCAST_IP);
}
udpPacket.setSourcePort(UDP.DHCP_SERVER_PORT);
if (directlyConnected(dhcpPayload)) {
udpPacket.setDestinationPort(UDP.DHCP_CLIENT_PORT);
} else {
// TODO Implement component config to support for both L2 and L3 relay
// L2 relay expects destination port to be CLIENT_PORT while L3 relay expects SERVER_PORT
// Currently we only support L2 relay for DHCPv4
udpPacket.setDestinationPort(UDP.DHCP_CLIENT_PORT);
}
udpPacket.setPayload(dhcpPayload);
ipv4Packet.setPayload(udpPacket);
etherReply.setPayload(ipv4Packet);
return InternalPacket.internalPacket(etherReply, clientInterface.connectPoint());
}
use of org.onosproject.dhcprelay.store.DhcpRecord in project onos by opennetworkinglab.
the class Dhcp4HandlerImpl method writeRequestDhcpRecord.
/**
* Writes DHCP record to the store according to the request DHCP packet (Discover, Request).
*
* @param location the location which DHCP packet comes from
* @param ethernet the DHCP packet
* @param dhcpPayload the DHCP payload
*/
private void writeRequestDhcpRecord(ConnectPoint location, Ethernet ethernet, DHCP dhcpPayload) {
VlanId vlanId = VlanId.vlanId(ethernet.getVlanID());
MacAddress macAddress = MacAddress.valueOf(dhcpPayload.getClientHardwareAddress());
HostId hostId = HostId.hostId(macAddress, vlanId);
DhcpRecord record = dhcpRelayStore.getDhcpRecord(hostId).orElse(null);
if (record == null) {
record = new DhcpRecord(HostId.hostId(macAddress, vlanId));
} else {
record = record.clone();
}
record.addLocation(new HostLocation(location, System.currentTimeMillis()));
record.ip4Status(dhcpPayload.getPacketType());
record.setDirectlyConnected(directlyConnected(dhcpPayload));
if (!directlyConnected(dhcpPayload)) {
// Update gateway mac address if the host is not directly connected
record.nextHop(ethernet.getSourceMAC());
}
record.updateLastSeen();
dhcpRelayStore.updateDhcpRecord(HostId.hostId(macAddress, vlanId), record);
}
use of org.onosproject.dhcprelay.store.DhcpRecord in project onos by opennetworkinglab.
the class Dhcp4HandlerImpl method writeResponseDhcpRecord.
/**
* Writes DHCP record to the store according to the response DHCP packet (Offer, Ack).
*
* @param ethernet the DHCP packet
* @param dhcpPayload the DHCP payload
*/
private void writeResponseDhcpRecord(Ethernet ethernet, DHCP dhcpPayload) {
Optional<Interface> outInterface = getClientInterface(ethernet, dhcpPayload);
if (!outInterface.isPresent()) {
log.warn("Failed to determine where to send {}", dhcpPayload.getPacketType());
return;
}
Interface outIface = outInterface.get();
ConnectPoint location = outIface.connectPoint();
if (!location.port().hasName()) {
location = translateSwitchPort(location);
}
VlanId vlanId = getVlanIdFromRelayAgentOption(dhcpPayload);
if (vlanId == null) {
vlanId = outIface.vlan();
}
MacAddress macAddress = MacAddress.valueOf(dhcpPayload.getClientHardwareAddress());
HostId hostId = HostId.hostId(macAddress, vlanId);
DhcpRecord record = dhcpRelayStore.getDhcpRecord(hostId).orElse(null);
if (record == null) {
record = new DhcpRecord(HostId.hostId(macAddress, vlanId));
} else {
record = record.clone();
}
record.addLocation(new HostLocation(location, System.currentTimeMillis()));
if (dhcpPayload.getPacketType() == DHCP.MsgType.DHCPACK) {
record.ip4Address(Ip4Address.valueOf(dhcpPayload.getYourIPAddress()));
}
record.ip4Status(dhcpPayload.getPacketType());
record.setDirectlyConnected(directlyConnected(dhcpPayload));
record.updateLastSeen();
dhcpRelayStore.updateDhcpRecord(HostId.hostId(macAddress, vlanId), record);
}
use of org.onosproject.dhcprelay.store.DhcpRecord in project onos by opennetworkinglab.
the class Dhcp4HandlerImpl method handleLeaseQueryActivateMsg.
private void handleLeaseQueryActivateMsg(Ethernet packet, DHCP dhcpPayload) {
log.debug("LQ: Got DHCPLEASEACTIVE packet!");
if (learnRouteFromLeasequery) {
// TODO: release the ip address from client
MacAddress clientMacAddress = MacAddress.valueOf(dhcpPayload.getClientHardwareAddress());
VlanId vlanId = VlanId.vlanId(packet.getVlanID());
HostId hostId = HostId.hostId(clientMacAddress, vlanId);
DhcpRecord record = dhcpRelayStore.getDhcpRecord(hostId).orElse(null);
if (record == null) {
log.warn("Can't find record for host {} when processing DHCPLEASEACTIVE", hostId);
return;
}
// need to update routes
log.debug("Lease Query for Client results in DHCPLEASEACTIVE - route needs to be modified");
// get current route
// find the ip of that client with the DhcpRelay store
Ip4Address clientIP = record.ip4Address().orElse(null);
log.debug("LQ: IP of host is " + clientIP.getIp4Address());
MacAddress nextHopMac = record.nextHop().orElse(null);
log.debug("LQ: MAC of resulting *OLD* NH for that host is " + nextHopMac.toString());
// find the new NH by looking at the src MAC of the dhcp request
// from the LQ store
MacAddress newNextHopMac = record.nextHopTemp().orElse(null);
log.debug("LQ: MAC of resulting *NEW* NH for that host is " + newNextHopMac.toString());
log.debug("LQ: updating dhcp relay record with new NH");
record.nextHop(newNextHopMac);
// find the next hop IP from its mac
HostId gwHostId = HostId.hostId(newNextHopMac, vlanId);
Host gwHost = hostService.getHost(gwHostId);
if (gwHost == null) {
log.warn("Can't find gateway for new NH host " + gwHostId);
return;
}
Ip4Address nextHopIp = gwHost.ipAddresses().stream().filter(IpAddress::isIp4).map(IpAddress::getIp4Address).findFirst().orElse(null);
if (nextHopIp == null) {
log.warn("Can't find IP address of gateway " + gwHost);
return;
}
log.debug("LQ: *NEW* NH IP for host is " + nextHopIp.getIp4Address());
Route route = new Route(Route.Source.DHCP, clientIP.toIpPrefix(), nextHopIp);
routeStore.updateRoute(route);
}
// and forward to client
InternalPacket ethernetPacket = processLeaseQueryFromServer(packet);
if (ethernetPacket != null) {
sendResponseToClient(ethernetPacket, dhcpPayload);
}
}
use of org.onosproject.dhcprelay.store.DhcpRecord in project onos by opennetworkinglab.
the class Dhcp4HandlerImpl method getVlanIdFromDhcpRecord.
/**
* Get the required vlanId in case the DCHP record has more than one vlanId for a given MAC.
*
* @param mac MAC address of the DHCP client
* @param vlan Expected vlan of the DHCP client
*/
private VlanId getVlanIdFromDhcpRecord(MacAddress mac, VlanId vlan) {
// Get all the DHCP records matching with the mac address
// If only one entry is present then pick the vlan of that entry
// If more then one entry is present then look for an entry with matching vlan
// else return null
Collection<DhcpRecord> records = dhcpRelayStore.getDhcpRecords();
List<DhcpRecord> filteredRecords = new ArrayList<>();
for (DhcpRecord e : records) {
if (e.macAddress().equals(mac)) {
filteredRecords.add(e);
}
}
log.debug("getVlanIdFromDhcpRecord mac: {} vlan: {}", mac, vlan);
log.debug("filteredRecords are: {}", filteredRecords);
if (filteredRecords.size() == 1) {
log.debug("Only one DHCP record entry. Returning back the vlan of that DHCP record: {}", filteredRecords);
return filteredRecords.get(0).vlanId();
}
// Check in the DHCP filtered record for matching vlan
for (DhcpRecord e : filteredRecords) {
if (e.vlanId().equals(vlan)) {
log.debug("Found a matching vlan entry in the DHCP record:{}", e);
return vlan;
}
}
// Found nothing return null
log.debug("Returning null as no matching or more than one matching entry found");
return null;
}
Aggregations