[CORD-1735] Add "relayAgentIps" option to DHCP relay application config
Change-Id: I2d95b5a285c81c15002ad94686b26ce03910198e
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp4HandlerImpl.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp4HandlerImpl.java
index 4d2bebb..0df73e4 100644
--- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp4HandlerImpl.java
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp4HandlerImpl.java
@@ -117,6 +117,7 @@
private MacAddress dhcpConnectMac = null;
private VlanId dhcpConnectVlan = null;
private Ip4Address dhcpGatewayIp = null;
+ private Ip4Address relayAgentIp = null;
@Activate
protected void activate() {
@@ -128,6 +129,12 @@
hostService.removeListener(hostListener);
this.dhcpConnectMac = null;
this.dhcpConnectVlan = null;
+
+ if (dhcpGatewayIp != null) {
+ hostService.stopMonitoringIp(dhcpGatewayIp);
+ } else if (dhcpServerIp != null) {
+ hostService.stopMonitoringIp(dhcpServerIp);
+ }
}
@Override
@@ -231,6 +238,8 @@
this.dhcpConnectVlan = host.vlan();
this.dhcpConnectMac = host.mac();
}
+
+ this.relayAgentIp = serverConfig.getRelayAgentIp4().orElse(null);
}
@Override
@@ -238,6 +247,7 @@
log.warn("Indirect config feature for DHCPv4 handler not implement yet");
}
+ @Override
public void processDhcpPacket(PacketContext context, BasePacket payload) {
checkNotNull(payload, "DHCP payload can't be null");
checkState(payload instanceof DHCP, "Payload is not a DHCP");
@@ -340,7 +350,7 @@
* @return the first interface IP; null if not exists an IP address in
* these interfaces
*/
- private Ip4Address getRelayAgentIPv4Address(Interface iface) {
+ private Ip4Address getFirstIpFromInterface(Interface iface) {
checkNotNull(iface, "Interface can't be null");
return iface.ipAddressesList().stream()
.map(InterfaceIpAddress::ipAddress)
@@ -398,9 +408,9 @@
log.warn("Can't get server interface, ignore");
return null;
}
- Ip4Address relayAgentIp = getRelayAgentIPv4Address(serverInterface);
- MacAddress relayAgentMac = serverInterface.mac();
- if (relayAgentIp == null || relayAgentMac == null) {
+ Ip4Address ipFacingServer = getFirstIpFromInterface(serverInterface);
+ MacAddress macFacingServer = serverInterface.mac();
+ if (ipFacingServer == null || macFacingServer == null) {
log.warn("No IP address for server Interface {}", serverInterface);
return null;
}
@@ -414,11 +424,11 @@
}
// get dhcp header.
Ethernet etherReply = (Ethernet) ethernetPacket.clone();
- etherReply.setSourceMACAddress(relayAgentMac);
+ etherReply.setSourceMACAddress(macFacingServer);
etherReply.setDestinationMACAddress(dhcpConnectMac);
etherReply.setVlanID(dhcpConnectVlan.toShort());
IPv4 ipv4Packet = (IPv4) etherReply.getPayload();
- ipv4Packet.setSourceAddress(relayAgentIp.toInt());
+ ipv4Packet.setSourceAddress(ipFacingServer.toInt());
ipv4Packet.setDestinationAddress(dhcpServerIp.toInt());
UDP udpPacket = (UDP) ipv4Packet.getPayload();
DHCP dhcpPacket = (DHCP) udpPacket.getPayload();
@@ -459,6 +469,12 @@
dhcpPacket.setGatewayIPAddress(clientInterfaceIp.toInt());
}
+ // replace giaddr if relay agent IP is set
+ // FIXME for both direct and indirect case now, should be separated
+ if (relayAgentIp != null) {
+ dhcpPacket.setGatewayIPAddress(relayAgentIp.toInt());
+ }
+
udpPacket.setPayload(dhcpPacket);
// As a DHCP relay, the source port should be server port(67) instead
// of client port(68)
@@ -590,8 +606,8 @@
// we leave the srcMac from the original packet
// figure out the relay agent IP corresponding to the original request
- Ip4Address relayAgentIP = getRelayAgentIPv4Address(clientInterface);
- if (relayAgentIP == null) {
+ Ip4Address ipFacingClient = getFirstIpFromInterface(clientInterface);
+ 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(),
@@ -600,7 +616,7 @@
}
// SRC_IP: relay agent IP
// DST_IP: offered IP
- ipv4Packet.setSourceAddress(relayAgentIP.toInt());
+ ipv4Packet.setSourceAddress(ipFacingClient.toInt());
ipv4Packet.setDestinationAddress(dhcpPayload.getYourIPAddress());
udpPacket.setSourcePort(UDP.DHCP_SERVER_PORT);
if (directlyConnected(dhcpPayload)) {
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayManager.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayManager.java
index ba19fa7..e5c9973 100644
--- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayManager.java
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayManager.java
@@ -181,9 +181,6 @@
packetService.removeProcessor(dhcpRelayPacketProcessor);
cancelDhcpPackets();
cancelArpPackets();
- v4Handler.getDhcpGatewayIp().ifPresent(hostService::stopMonitoringIp);
- v4Handler.getDhcpServerIp().ifPresent(hostService::stopMonitoringIp);
- // TODO: DHCPv6 Handler
compCfgService.unregisterProperties(getClass(), false);
log.info("DHCP-RELAY Stopped");
@@ -236,15 +233,15 @@
// Ignore if config is not present
return;
}
- if (config instanceof DefaultDhcpRelayConfig) {
- DefaultDhcpRelayConfig defaultConfig = (DefaultDhcpRelayConfig) config;
- v4Handler.setDefaultDhcpServerConfigs(defaultConfig.dhcpServerConfigs());
- v6Handler.setDefaultDhcpServerConfigs(defaultConfig.dhcpServerConfigs());
- }
+
if (config instanceof IndirectDhcpRelayConfig) {
IndirectDhcpRelayConfig indirectConfig = (IndirectDhcpRelayConfig) config;
v4Handler.setIndirectDhcpServerConfigs(indirectConfig.dhcpServerConfigs());
v6Handler.setIndirectDhcpServerConfigs(indirectConfig.dhcpServerConfigs());
+ } else if (config instanceof DefaultDhcpRelayConfig) {
+ DefaultDhcpRelayConfig defaultConfig = (DefaultDhcpRelayConfig) config;
+ v4Handler.setDefaultDhcpServerConfigs(defaultConfig.dhcpServerConfigs());
+ v6Handler.setDefaultDhcpServerConfigs(defaultConfig.dhcpServerConfigs());
}
}
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/config/DefaultDhcpRelayConfig.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/config/DefaultDhcpRelayConfig.java
index 959c01b..daf97bf 100644
--- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/config/DefaultDhcpRelayConfig.java
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/config/DefaultDhcpRelayConfig.java
@@ -29,8 +29,6 @@
public class DefaultDhcpRelayConfig extends Config<ApplicationId> {
public static final String KEY = "default";
-
-
@Override
public boolean isValid() {
// check if all configs are valid
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/config/DhcpServerConfig.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/config/DhcpServerConfig.java
index 2451a7a..a5c304b 100644
--- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/config/DhcpServerConfig.java
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/config/DhcpServerConfig.java
@@ -33,12 +33,15 @@
private static final String DHCP_CONNECT_POINT = "dhcpServerConnectPoint";
private static final String DHCP_SERVER_IP = "serverIps";
private static final String DHCP_GATEWAY_IP = "gatewayIps";
+ private static final String RELAY_AGENT_IP = "relayAgentIps";
private ConnectPoint connectPoint;
private Ip4Address serverIp4Addr;
private Ip4Address gatewayIp4Addr;
+ private Ip4Address relayAgentIp4Addr;
private Ip6Address serverIp6Addr;
private Ip6Address gatewayIp6Addr;
+ private Ip6Address relayAgentIp6Addr;
protected DhcpServerConfig() {
// empty config not allowed here
@@ -68,22 +71,34 @@
}
});
- if (!config.has(DHCP_GATEWAY_IP)) {
- // gateway ip doesn't exist, ignore the gateway
- return;
+ if (config.has(DHCP_GATEWAY_IP)) {
+ ArrayNode gatewayIps = (ArrayNode) config.path(DHCP_GATEWAY_IP);
+ gatewayIps.forEach(node -> {
+ if (node.isTextual()) {
+ IpAddress ip = IpAddress.valueOf(node.asText());
+ if (ip.isIp4() && gatewayIp4Addr == null) {
+ gatewayIp4Addr = ip.getIp4Address();
+ }
+ if (ip.isIp6() && gatewayIp6Addr == null) {
+ gatewayIp6Addr = ip.getIp6Address();
+ }
+ }
+ });
}
- ArrayNode gatewayIps = (ArrayNode) config.path(DHCP_GATEWAY_IP);
- gatewayIps.forEach(node -> {
- if (node.isTextual()) {
- IpAddress ip = IpAddress.valueOf(node.asText());
- if (ip.isIp4() && gatewayIp4Addr == null) {
- gatewayIp4Addr = ip.getIp4Address();
+ if (config.has(RELAY_AGENT_IP)) {
+ ArrayNode relayAgentIps = (ArrayNode) config.path(RELAY_AGENT_IP);
+ relayAgentIps.forEach(node -> {
+ if (node.isTextual()) {
+ IpAddress ip = IpAddress.valueOf(node.asText());
+ if (ip.isIp4() && relayAgentIp4Addr == null) {
+ relayAgentIp4Addr = ip.getIp4Address();
+ }
+ if (ip.isIp6() && relayAgentIp6Addr == null) {
+ relayAgentIp6Addr = ip.getIp6Address();
+ }
}
- if (ip.isIp6() && gatewayIp6Addr == null) {
- gatewayIp6Addr = ip.getIp6Address();
- }
- }
- });
+ });
+ }
}
/**
@@ -146,4 +161,26 @@
public Optional<Ip6Address> getDhcpGatewayIp6() {
return Optional.ofNullable(gatewayIp6Addr);
}
+
+ /**
+ * Returns the optional IPv4 address for relay agent, if configured.
+ * This option is used if we want to replace the giaddr field in DHCPv4
+ * payload.
+ *
+ * @return the giaddr; empty value if not set
+ */
+ public Optional<Ip4Address> getRelayAgentIp4() {
+ return Optional.ofNullable(relayAgentIp4Addr);
+ }
+
+ /**
+ * Returns the optional IPv6 address for relay agent, if configured.
+ * This option is used if we want to replace the link-address field in DHCPv6
+ * payload.
+ *
+ * @return the giaddr; empty value if not set
+ */
+ public Optional<Ip6Address> getRelayAgentIp6() {
+ return Optional.ofNullable(relayAgentIp6Addr);
+ }
}
diff --git a/apps/dhcprelay/src/test/java/org/onosproject/dhcprelay/DhcpRelayManagerTest.java b/apps/dhcprelay/src/test/java/org/onosproject/dhcprelay/DhcpRelayManagerTest.java
index 71b3cef..45cfa23 100644
--- a/apps/dhcprelay/src/test/java/org/onosproject/dhcprelay/DhcpRelayManagerTest.java
+++ b/apps/dhcprelay/src/test/java/org/onosproject/dhcprelay/DhcpRelayManagerTest.java
@@ -27,6 +27,7 @@
import org.junit.Test;
import org.onlab.packet.ARP;
import org.onlab.packet.DHCP;
+import org.onlab.packet.DeserializationException;
import org.onlab.packet.Ethernet;
import org.onlab.packet.IPv4;
import org.onlab.packet.Ip4Address;
@@ -152,6 +153,9 @@
SERVER_IFACE_MAC,
SERVER_VLAN);
+ // Relay agent config
+ private static final Ip4Address RELAY_AGENT_IP = Ip4Address.valueOf("10.0.4.254");
+
// Components
private static final ApplicationId APP_ID = TestApplicationId.create(DhcpRelayManager.DHCP_RELAY_APP);
private static final DefaultDhcpRelayConfig CONFIG = new MockDefaultDhcpRelayConfig();
@@ -187,8 +191,8 @@
.andReturn(APP_ID).anyTimes();
manager.hostService = createNiceMock(HostService.class);
- expect(manager.hostService.getHostsByIp(anyObject())).andReturn(ImmutableSet.of(SERVER_HOST));
- expect(manager.hostService.getHost(OUTER_RELAY_HOST_ID)).andReturn(OUTER_RELAY_HOST);
+ expect(manager.hostService.getHostsByIp(anyObject())).andReturn(ImmutableSet.of(SERVER_HOST)).anyTimes();
+ expect(manager.hostService.getHost(OUTER_RELAY_HOST_ID)).andReturn(OUTER_RELAY_HOST).anyTimes();
packetService = new MockPacketService();
manager.packetService = packetService;
@@ -300,6 +304,24 @@
}
@Test
+ public void testWithRelayAgentConfig() throws DeserializationException {
+ manager.v4Handler
+ .setDefaultDhcpServerConfigs(ImmutableList.of(new MockDhcpServerConfig(RELAY_AGENT_IP)));
+ packetService.processPacket(new TestDhcpRequestPacketContext(CLIENT2_MAC,
+ CLIENT2_VLAN,
+ CLIENT2_CP,
+ INTERFACE_IP.ipAddress().getIp4Address(),
+ true));
+ OutboundPacket outPacket = packetService.emittedPacket;
+ byte[] outData = outPacket.data().array();
+ Ethernet eth = Ethernet.deserializer().deserialize(outData, 0, outData.length);
+ IPv4 ip = (IPv4) eth.getPayload();
+ UDP udp = (UDP) ip.getPayload();
+ DHCP dhcp = (DHCP) udp.getPayload();
+ assertEquals(RELAY_AGENT_IP.toInt(), dhcp.getGatewayIPAddress());
+ }
+
+ @Test
public void testArpRequest() throws Exception {
packetService.processPacket(new TestArpRequestPacketContext(CLIENT_INTERFACE));
OutboundPacket outboundPacket = packetService.emittedPacket;
@@ -319,11 +341,27 @@
@Override
public List<DhcpServerConfig> dhcpServerConfigs() {
- return ImmutableList.of(new MockDhcpServerConfig());
+ return ImmutableList.of(new MockDhcpServerConfig(null));
}
}
private static class MockDhcpServerConfig extends DhcpServerConfig {
+ Ip4Address relayAgentIp;
+
+ /**
+ * Create mocked version DHCP server config.
+ *
+ * @param relayAgentIp the relay agent Ip config; null if we don't need it
+ */
+ public MockDhcpServerConfig(Ip4Address relayAgentIp) {
+ this.relayAgentIp = relayAgentIp;
+ }
+
+ @Override
+ public Optional<Ip4Address> getRelayAgentIp4() {
+ return Optional.ofNullable(relayAgentIp);
+ }
+
@Override
public Optional<ConnectPoint> getDhcpServerConnectPoint() {
return Optional.of(SERVER_CONNECT_POINT);
diff --git a/apps/dhcprelay/src/test/resources/dhcp-relay.json b/apps/dhcprelay/src/test/resources/dhcp-relay.json
index bd90b7a..dc724ee 100644
--- a/apps/dhcprelay/src/test/resources/dhcp-relay.json
+++ b/apps/dhcprelay/src/test/resources/dhcp-relay.json
@@ -5,13 +5,15 @@
{
"dhcpServerConnectPoint": "of:0000000000000002/2",
"serverIps": ["172.168.10.2", "2000::200:1"],
- "gatewayIps": ["192.168.10.254", "1000::100:1"]
+ "gatewayIps": ["192.168.10.254", "1000::100:1"],
+ "relayAgentIps": ["10.0.0.1", "1000:100::100:1"]
}
],
"indirect": [
{
"dhcpServerConnectPoint": "of:0000000000000002/3",
- "serverIps": ["172.168.10.3"]
+ "serverIps": ["172.168.10.3"],
+ "relayAgentIps": ["10.0.1.1"]
}
]
}