[CORD-2066] Router to indirect IPv6 addresses are unresolvable
Change-Id: I8a6cbade1d995692de40a4b5418b8fa6c60f10af
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerImpl.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerImpl.java
index d816a96..abcdcb6 100644
--- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerImpl.java
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp6HandlerImpl.java
@@ -631,6 +631,10 @@
Ethernet clientPacket, IPv6 clientIpv6,
Interface clientInterface) {
log.debug("extractPrefix enters {}", dhcp6Packet);
+ VlanId vlanId = clientInterface.vlan();
+ MacAddress clientMac = clientPacket.getSourceMAC();
+ log.debug("client mac {} client vlan {}", HexString.toHexString(clientMac.toBytes(), ":"), vlanId);
+
// add host or route
if (isDhcp6Release(dhcp6Packet)) {
IpAddress ip = null;
@@ -638,13 +642,9 @@
// Add to host store if it is connected to network directly
ip = extractIpAddress(dhcp6Packet);
if (ip != null) {
- VlanId vlanId = clientInterface.vlan();
- MacAddress clientMac = clientPacket.getSourceMAC();
+
HostId hostId = HostId.hostId(clientMac, vlanId);
log.debug("remove Host {} ip for directly connected.", hostId.toString());
-
- log.debug("client mac {} client vlan {}", HexString.toHexString(clientMac.toBytes(), ":"), vlanId);
-
// Remove host's ip of when dhcp release msg is received
providerService.removeIpFromHost(hostId, ip);
} else {
@@ -652,7 +652,13 @@
}
} else {
// Remove from route store if it is not connected to network directly
- IpAddress nextHopIp = IpAddress.valueOf(IpAddress.Version.INET6, clientIpv6.getSourceAddress());
+ // pick out the first link-local ip address
+ IpAddress nextHopIp = getFirstIpByHost(clientMac, vlanId);
+ if (nextHopIp == null) {
+ log.warn("Can't find link-local IP address of gateway mac {} vlanId {}",
+ clientMac, vlanId);
+ return;
+ }
DHCP6 leafDhcp = getDhcp6Leaf(dhcp6Packet);
ip = extractIpAddress(leafDhcp);
@@ -695,6 +701,7 @@
MacAddress clientMac,
Interface clientInterface) {
log.debug("addHostOrRoute entered.");
+ VlanId vlanId = clientInterface.vlan();
// add host or route
if (isDhcp6Reply(dhcp6Relay)) {
IpAddress ip = null;
@@ -705,7 +712,6 @@
Set<IpAddress> ips = Sets.newHashSet(ip);
// FIXME: we should use vlan id from original packet (solicit, request)
- VlanId vlanId = clientInterface.vlan();
HostId hostId = HostId.hostId(clientMac, vlanId);
Host host = hostService.getHost(hostId);
HostLocation hostLocation = new HostLocation(clientInterface.connectPoint(),
@@ -732,7 +738,13 @@
}
} else {
// Add to route store if it does not connect to network directly
- IpAddress nextHopIp = IpAddress.valueOf(IpAddress.Version.INET6, dhcp6Relay.getPeerAddress());
+ // pick out the first link-local ip address
+ IpAddress nextHopIp = getFirstIpByHost(clientMac, vlanId);
+ if (nextHopIp == null) {
+ log.warn("Can't find link-local IP address of gateway mac {} vlanId {}",
+ clientMac, vlanId);
+ return;
+ }
DHCP6 leafDhcp = getDhcp6Leaf(embeddedDhcp6);
ip = extractIpAddress(leafDhcp);
@@ -809,69 +821,44 @@
if (this.dhcpServerConnectPoint == null) {
log.warn("DHCP6 server connection point direct {} directConn {} indirectConn {} is not set up yet",
directConnFlag, this.dhcpServerConnectPoint, this.indirectDhcpServerConnectPoint);
- return null;
- }
+ return null;
+ }
- etherReply.setDestinationMACAddress(this.dhcpConnectMac);
- etherReply.setVlanID(this.dhcpConnectVlan.toShort());
+ etherReply.setDestinationMACAddress(this.dhcpConnectMac);
+ etherReply.setVlanID(this.dhcpConnectVlan.toShort());
- IPv6 ipv6Packet = (IPv6) etherReply.getPayload();
- Ip6Address peerAddress = null;
- if (directConnFlag) {
- peerAddress = Ip6Address.valueOf(ipv6Packet.getSourceAddress());
- } else {
- MacAddress gwOrClientMac = MacAddress.valueOf(clientPacket.getSourceMACAddress());
- VlanId vlanId = VlanId.vlanId(clientPacket.getVlanID());
- HostId gwOrClientHostId = HostId.hostId(gwOrClientMac, vlanId);
- Host gwOrClientHost = hostService.getHost(gwOrClientHostId);
+ IPv6 ipv6Packet = (IPv6) etherReply.getPayload();
+ byte[] peerAddress = clientIpv6.getSourceAddress();
+ ipv6Packet.setSourceAddress(ipFacingServer.toOctets());
+ ipv6Packet.setDestinationAddress(this.dhcpServerIp.toOctets());
- if (gwOrClientHost == null) {
- log.warn("Can't find client gateway/server host {}", gwOrClientHostId);
- return null;
- }
- // pick out the first gloabl ip address
- peerAddress = gwOrClientHost.ipAddresses().stream()
- .filter(IpAddress::isIp6).filter(ip6 -> !ip6.isLinkLocal())
- .map(IpAddress::getIp6Address).findFirst().orElse(null);
+ UDP udpPacket = (UDP) ipv6Packet.getPayload();
+ udpPacket.setSourcePort(UDP.DHCP_V6_SERVER_PORT);
+ DHCP6 dhcp6Packet = (DHCP6) udpPacket.getPayload();
+ byte[] dhcp6PacketByte = dhcp6Packet.serialize();
- if (peerAddress == null) {
- log.warn("Can't find client gateway/server for mac {} ip {}", gwOrClientMac,
- HexString.toHexString(ipv6Packet.getSourceAddress()));
- log.warn("Can't find IP address of client gateway/ClienHost address {} for peerAddress",
- gwOrClientHost);
- return null;
- }
- }
- ipv6Packet.setSourceAddress(ipFacingServer.toOctets());
- ipv6Packet.setDestinationAddress(this.dhcpServerIp.toOctets());
+ // notify onos and quagga to release PD
+ //releasePD(dhcp6Packet);
+ ConnectPoint clientConnectionPoint = context.inPacket().receivedFrom();
+ VlanId vlanIdInUse = VlanId.vlanId(clientPacket.getVlanID());
+ Interface clientInterface = interfaceService.getInterfacesByPort(clientConnectionPoint)
+ .stream().filter(iface -> interfaceContainsVlan(iface, vlanIdInUse))
+ .findFirst().orElse(null);
- UDP udpPacket = (UDP) ipv6Packet.getPayload();
- udpPacket.setSourcePort(UDP.DHCP_V6_SERVER_PORT);
- DHCP6 dhcp6Packet = (DHCP6) udpPacket.getPayload();
- byte[] dhcp6PacketByte = dhcp6Packet.serialize();
+ removeHostOrRoute(directConnFlag, dhcp6Packet, clientPacket, clientIpv6, clientInterface);
- // notify onos and quagga to release PD
- //releasePD(dhcp6Packet);
- ConnectPoint clientConnectionPoint = context.inPacket().receivedFrom();
- VlanId vlanIdInUse = VlanId.vlanId(clientPacket.getVlanID());
- Interface clientInterface = interfaceService.getInterfacesByPort(clientConnectionPoint)
- .stream().filter(iface -> interfaceContainsVlan(iface, vlanIdInUse))
- .findFirst().orElse(null);
+ DHCP6 dhcp6Relay = new DHCP6();
+ dhcp6Relay.setMsgType(DHCP6.MsgType.RELAY_FORW.value());
+ // link address: server uses the address to identify the link on which the client
+ // is located.
+ if (directConnFlag) {
+ dhcp6Relay.setLinkAddress(relayAgentIp.toOctets());
+ log.debug("direct connection: relayAgentIp obtained dynamically {}",
+ HexString.toHexString(relayAgentIp.toOctets(), ":"));
- removeHostOrRoute(directConnFlag, dhcp6Packet, clientPacket, clientIpv6, clientInterface);
-
- DHCP6 dhcp6Relay = new DHCP6();
- dhcp6Relay.setMsgType(DHCP6.MsgType.RELAY_FORW.value());
- // link address: server uses the address to identify the link on which the client
- // is located.
- if (directConnFlag) {
- dhcp6Relay.setLinkAddress(relayAgentIp.toOctets());
- log.debug("direct connection: relayAgentIp obtained dynamically {}",
- HexString.toHexString(relayAgentIp.toOctets(), ":"));
-
- } else {
- if (this.indirectDhcpServerIp == null) {
- log.warn("indirect DhcpServerIp not available, use default DhcpServerIp {}",
+ } else {
+ if (this.indirectDhcpServerIp == null) {
+ log.warn("indirect DhcpServerIp not available, use default DhcpServerIp {}",
HexString.toHexString(this.dhcpServerIp.toOctets()));
} else {
// Indirect case, replace destination to indirect dhcp server if exist
@@ -893,76 +880,76 @@
dhcp6Relay.setLinkAddress(relayAgentIp.toOctets());
log.warn("indirect connection: relayAgentIp NOT availale from config file! Use dynamic. {}",
HexString.toHexString(relayAgentIp.toOctets(), ":"));
- } else {
- dhcp6Relay.setLinkAddress(this.indirectRelayAgentIpFromCfg.toOctets());
- log.debug("indirect connection: relayAgentIp from config file is available! {}",
- HexString.toHexString(this.indirectRelayAgentIpFromCfg.toOctets(), ":"));
- }
- }
+ } else {
+ dhcp6Relay.setLinkAddress(this.indirectRelayAgentIpFromCfg.toOctets());
+ log.debug("indirect connection: relayAgentIp from config file is available! {}",
+ HexString.toHexString(this.indirectRelayAgentIpFromCfg.toOctets(), ":"));
+ }
+ }
- // peer address: address of the client or relay agent from which
- // the message to be relayed was received.
- dhcp6Relay.setPeerAddress(peerAddress.toOctets());
- List<Dhcp6Option> options = new ArrayList<Dhcp6Option>();
+ // peer address: address of the client or relay agent from which
+ // the message to be relayed was received.
+ dhcp6Relay.setPeerAddress(peerAddress);
+ List<Dhcp6Option> options = new ArrayList<Dhcp6Option>();
- // directly connected case, hop count is zero
- // otherwise, hop count + 1
- if (directConnFlag) {
- dhcp6Relay.setHopCount((byte) 0);
- } else {
- dhcp6Relay.setHopCount((byte) (dhcp6Packet.getHopCount() + 1));
- }
+ // directly connected case, hop count is zero
+ // otherwise, hop count + 1
+ if (directConnFlag) {
+ dhcp6Relay.setHopCount((byte) 0);
+ } else {
+ dhcp6Relay.setHopCount((byte) (dhcp6Packet.getHopCount() + 1));
+ }
- // create relay message option
- Dhcp6Option relayMessage = new Dhcp6Option();
- relayMessage.setCode(DHCP6.OptionCode.RELAY_MSG.value());
- relayMessage.setLength((short) dhcp6PacketByte.length);
- relayMessage.setData(dhcp6PacketByte);
- options.add(relayMessage);
+ // create relay message option
+ Dhcp6Option relayMessage = new Dhcp6Option();
+ relayMessage.setCode(DHCP6.OptionCode.RELAY_MSG.value());
+ relayMessage.setLength((short) dhcp6PacketByte.length);
+ relayMessage.setData(dhcp6PacketByte);
+ options.add(relayMessage);
- // create interfaceId option
- String inPortString = "-" + context.inPacket().receivedFrom().toString() + ":";
- Dhcp6Option interfaceId = new Dhcp6Option();
- interfaceId.setCode(DHCP6.OptionCode.INTERFACE_ID.value());
- byte[] clientSoureMacBytes = clientPacket.getSourceMACAddress();
- byte[] inPortStringBytes = inPortString.getBytes();
- byte[] vlanIdBytes = new byte[2];
- vlanIdBytes[0] = (byte) (clientPacket.getVlanID() & 0xff);
- vlanIdBytes[1] = (byte) ((clientPacket.getVlanID() >> 8) & 0xff);
- byte[] interfaceIdBytes = new byte[clientSoureMacBytes.length +
- inPortStringBytes.length + vlanIdBytes.length];
- log.debug("Length: interfaceIdBytes {} clientSoureMacBytes {} inPortStringBytes {} vlan {}",
- interfaceIdBytes.length, clientSoureMacBytes.length, inPortStringBytes.length,
- vlanIdBytes.length);
+ // create interfaceId option
+ String inPortString = "-" + context.inPacket().receivedFrom().toString() + ":";
+ Dhcp6Option interfaceId = new Dhcp6Option();
+ interfaceId.setCode(DHCP6.OptionCode.INTERFACE_ID.value());
+ byte[] clientSoureMacBytes = clientPacket.getSourceMACAddress();
+ byte[] inPortStringBytes = inPortString.getBytes();
+ byte[] vlanIdBytes = new byte[2];
+ vlanIdBytes[0] = (byte) (clientPacket.getVlanID() & 0xff);
+ vlanIdBytes[1] = (byte) ((clientPacket.getVlanID() >> 8) & 0xff);
+ byte[] interfaceIdBytes = new byte[clientSoureMacBytes.length +
+ inPortStringBytes.length + vlanIdBytes.length];
+ log.debug("Length: interfaceIdBytes {} clientSoureMacBytes {} inPortStringBytes {} vlan {}",
+ interfaceIdBytes.length, clientSoureMacBytes.length, inPortStringBytes.length,
+ vlanIdBytes.length);
- System.arraycopy(clientSoureMacBytes, 0, interfaceIdBytes, 0, clientSoureMacBytes.length);
- System.arraycopy(inPortStringBytes, 0, interfaceIdBytes, clientSoureMacBytes.length, inPortStringBytes.length);
- System.arraycopy(vlanIdBytes, 0, interfaceIdBytes, clientSoureMacBytes.length + inPortStringBytes.length,
- vlanIdBytes.length);
+ System.arraycopy(clientSoureMacBytes, 0, interfaceIdBytes, 0, clientSoureMacBytes.length);
+ System.arraycopy(inPortStringBytes, 0, interfaceIdBytes, clientSoureMacBytes.length, inPortStringBytes.length);
+ System.arraycopy(vlanIdBytes, 0, interfaceIdBytes, clientSoureMacBytes.length + inPortStringBytes.length,
+ vlanIdBytes.length);
- interfaceId.setData(interfaceIdBytes);
- interfaceId.setLength((short) interfaceIdBytes.length);
+ interfaceId.setData(interfaceIdBytes);
+ interfaceId.setLength((short) interfaceIdBytes.length);
- options.add(interfaceId);
+ options.add(interfaceId);
- log.debug("interfaceId write srcMac {} portString {}",
- HexString.toHexString(clientSoureMacBytes, ":"), inPortString);
- dhcp6Relay.setOptions(options);
- udpPacket.setPayload(dhcp6Relay);
- udpPacket.resetChecksum();
- ipv6Packet.setPayload(udpPacket);
- ipv6Packet.setHopLimit((byte) 64);
- etherReply.setPayload(ipv6Packet);
+ log.debug("interfaceId write srcMac {} portString {}",
+ HexString.toHexString(clientSoureMacBytes, ":"), inPortString);
+ dhcp6Relay.setOptions(options);
+ udpPacket.setPayload(dhcp6Relay);
+ udpPacket.resetChecksum();
+ ipv6Packet.setPayload(udpPacket);
+ ipv6Packet.setHopLimit((byte) 64);
+ etherReply.setPayload(ipv6Packet);
- if (directConnFlag) {
- return new InternalPacket(etherReply, this.dhcpServerConnectPoint);
- } else {
- if (this.indirectDhcpServerIp == null) {
- return new InternalPacket(etherReply, this.dhcpServerConnectPoint);
- } else {
- return new InternalPacket(etherReply, this.indirectDhcpServerConnectPoint);
- }
- }
+ if (directConnFlag) {
+ return new InternalPacket(etherReply, this.dhcpServerConnectPoint);
+ } else {
+ if (this.indirectDhcpServerIp == null) {
+ return new InternalPacket(etherReply, this.dhcpServerConnectPoint);
+ } else {
+ return new InternalPacket(etherReply, this.indirectDhcpServerConnectPoint);
+ }
+ }
}
/**
@@ -1514,4 +1501,30 @@
flowObjectiveService.apply(deviceId, fwd);
});
}
+
+ /**
+ * Find first ipaddress for a given Host info i.e. mac and vlan.
+ *
+ * @param clientMac client mac
+ * @param vlanId packet's vlan
+ * @return next-hop link-local ipaddress for a given host
+ */
+ private IpAddress getFirstIpByHost(MacAddress clientMac, VlanId vlanId) {
+ IpAddress nextHopIp;
+ // pick out the first link-local ip address
+ HostId gwHostId = HostId.hostId(clientMac, vlanId);
+ Host gwHost = hostService.getHost(gwHostId);
+ if (gwHost == null) {
+ log.warn("Can't find gateway host for hostId {}", gwHostId);
+ return null;
+ }
+ nextHopIp = gwHost.ipAddresses()
+ .stream()
+ .filter(IpAddress::isIp6)
+ .filter(ip6 -> ip6.isLinkLocal())
+ .map(IpAddress::getIp6Address)
+ .findFirst()
+ .orElse(null);
+ return nextHopIp;
+ }
}
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 eb24ae2..7efed1a 100644
--- a/apps/dhcprelay/src/test/java/org/onosproject/dhcprelay/DhcpRelayManagerTest.java
+++ b/apps/dhcprelay/src/test/java/org/onosproject/dhcprelay/DhcpRelayManagerTest.java
@@ -178,11 +178,13 @@
CLIENT2_VLAN_NATIVE);
private static final VlanId CLIENT_BOGUS_VLAN = VlanId.vlanId("108");
-
// Outer relay information
- private static final Ip4Address OUTER_RELAY_IP = Ip4Address.valueOf("10.0.5.253");
+ private static final Ip4Address OUTER_RELAY_IP = Ip4Address.valueOf("10.0.6.253");
private static final Ip6Address OUTER_RELAY_IP_V6 = Ip6Address.valueOf("2001:db8:1::4");
- private static final Set<IpAddress> OUTER_RELAY_IPS = ImmutableSet.of(OUTER_RELAY_IP, OUTER_RELAY_IP_V6);
+ private static final Ip6Address OUTER_RELAY_LL_IP_V6 = Ip6Address.valueOf("fe80::200:0102:0304:0501");
+ private static final Set<IpAddress> OUTER_RELAY_IPS = ImmutableSet.of(OUTER_RELAY_IP,
+ OUTER_RELAY_IP_V6,
+ OUTER_RELAY_LL_IP_V6);
private static final MacAddress OUTER_RELAY_MAC = MacAddress.valueOf("00:01:02:03:04:05");
private static final VlanId OUTER_RELAY_VLAN = VlanId.NONE;
private static final ConnectPoint OUTER_RELAY_CP = ConnectPoint.deviceConnectPoint("of:0000000000000001/2");
@@ -286,7 +288,20 @@
.andReturn(APP_ID).anyTimes();
manager.hostService = createNiceMock(HostService.class);
- expect(manager.hostService.getHostsByIp(anyObject())).andReturn(ImmutableSet.of(SERVER_HOST)).anyTimes();
+
+ expect(manager.hostService.getHostsByIp(OUTER_RELAY_IP_V6))
+ .andReturn(ImmutableSet.of(OUTER_RELAY_HOST)).anyTimes();
+ expect(manager.hostService.getHostsByIp(SERVER_IP))
+ .andReturn(ImmutableSet.of(SERVER_HOST)).anyTimes();
+ expect(manager.hostService.getHostsByIp(SERVER_IP_V6))
+ .andReturn(ImmutableSet.of(SERVER_HOST)).anyTimes();
+ expect(manager.hostService.getHostsByIp(GATEWAY_IP))
+ .andReturn(ImmutableSet.of(SERVER_HOST)).anyTimes();
+ expect(manager.hostService.getHostsByIp(GATEWAY_IP_V6))
+ .andReturn(ImmutableSet.of(SERVER_HOST)).anyTimes();
+ expect(manager.hostService.getHostsByIp(CLIENT_LL_IP_V6))
+ .andReturn(ImmutableSet.of(EXISTS_HOST)).anyTimes();
+
expect(manager.hostService.getHost(OUTER_RELAY_HOST_ID)).andReturn(OUTER_RELAY_HOST).anyTimes();
packetService = new MockPacketService();
@@ -641,7 +656,7 @@
CLIENT_CP, CLIENT_MAC,
CLIENT_VLAN,
INTERFACE_IP_V6.ipAddress().getIp6Address(),
- 0));
+ 0, false, CLIENT_VLAN));
verify(mockHostProviderService);
assertEquals(0, mockRouteStore.routes.size());
@@ -685,7 +700,7 @@
CLIENT2_MAC,
CLIENT2_VLAN,
OUTER_RELAY_IP_V6,
- 1));
+ 1, false, CLIENT2_VLAN));
// won't trigger the host provider service
verify(mockHostProviderService);
@@ -750,9 +765,11 @@
packetService.processPacket(new TestDhcp6ReplyPacketContext(DHCP6.MsgType.REPLY.value(),
CLIENT2_CP,
CLIENT2_MAC,
- CLIENT_BOGUS_VLAN, // mismatch
+ CLIENT2_VLAN,
INTERFACE_IP_V6.ipAddress().getIp6Address(),
- 1));
+ 1, true,
+ CLIENT_BOGUS_VLAN // mismatch
+ ));
// won't trigger the host provider service
verify(mockHostProviderService);
@@ -789,7 +806,7 @@
new TestDhcp6ReplyPacketContext(DHCP6.MsgType.REPLY.value(),
CLIENT_DH_CP, CLIENT_MAC, CLIENT_VLAN,
INTERFACE_IP_V6.ipAddress().getIp6Address(),
- 0);
+ 0, false, CLIENT_VLAN);
reset(manager.hostService);
expect(manager.hostService.getHostsByIp(CLIENT_LL_IP_V6)).andReturn(ImmutableSet.of(EXISTS_HOST)).anyTimes();
@@ -1377,7 +1394,7 @@
Ethernet eth = new Ethernet();
if (relayLevel > 0) {
eth.setEtherType(Ethernet.TYPE_IPV6)
- .setVlanID(vlanId.toShort())
+ .setVlanID(OUTER_RELAY_VLAN.toShort())
.setSourceMACAddress(OUTER_RELAY_MAC)
.setDestinationMACAddress(MacAddress.valueOf("33:33:00:01:00:02"))
.setPayload(ipv6);
@@ -1407,7 +1424,7 @@
public TestDhcp6ReplyPacketContext(byte msgType, ConnectPoint clientCp, MacAddress clientMac,
VlanId clientVlan, Ip6Address clientGwAddr,
- int relayLevel) {
+ int relayLevel, boolean overWriteFlag, VlanId overWriteVlan) {
super(0, null, null, false);
@@ -1415,7 +1432,14 @@
buildDhcp6Packet(dhcp6Payload, msgType,
IP_FOR_CLIENT_V6,
PREFIX_FOR_CLIENT_V6);
- byte[] interfaceId = buildInterfaceId(clientMac, clientVlan.toShort(), clientCp);
+ byte[] interfaceId = null;
+ if (relayLevel > 0) {
+ interfaceId = buildInterfaceId(OUTER_RELAY_MAC,
+ overWriteFlag ? overWriteVlan.toShort() : OUTER_RELAY_VLAN.toShort(),
+ OUTER_RELAY_CP);
+ } else {
+ interfaceId = buildInterfaceId(clientMac, clientVlan.toShort(), clientCp);
+ }
DHCP6 dhcp6 = new DHCP6();
buildRelayMsg(dhcp6, DHCP6.MsgType.RELAY_REPL.value(),
INTERFACE_IP_V6.ipAddress().getIp6Address(),