blob: afda3bdfcc924ac5a4429efbd2b2a85583215812 [file] [log] [blame]
Yi Tseng7a38f9a2017-06-09 14:36:40 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Yi Tseng7a38f9a2017-06-09 14:36:40 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.dhcprelay;
17
Yi Tseng51f1be92017-09-01 17:24:57 -070018import com.fasterxml.jackson.databind.JsonNode;
19import com.fasterxml.jackson.databind.ObjectMapper;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070020import com.google.common.collect.ImmutableList;
21import com.google.common.collect.ImmutableSet;
22import com.google.common.collect.Lists;
23import com.google.common.collect.Maps;
24import com.google.common.collect.Sets;
Yi Tseng525ff402017-10-23 19:39:39 -070025import com.google.common.collect.Streams;
Yi Tseng51f1be92017-09-01 17:24:57 -070026import com.google.common.io.Resources;
Yi Tseng440e2b72017-08-24 14:47:34 -070027import org.apache.commons.io.Charsets;
Yi Tseng25bfe372017-11-03 16:27:32 -070028import org.apache.commons.lang3.tuple.Pair;
Yi Tseng51f1be92017-09-01 17:24:57 -070029import org.easymock.Capture;
30import org.easymock.CaptureType;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070031import org.easymock.EasyMock;
32import org.junit.After;
33import org.junit.Before;
34import org.junit.Test;
35import org.onlab.packet.ARP;
36import org.onlab.packet.DHCP;
Yi Tseng3df7f9d2017-08-17 13:08:31 -070037import org.onlab.packet.DeserializationException;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070038import org.onlab.packet.Ethernet;
39import org.onlab.packet.IPv4;
40import org.onlab.packet.Ip4Address;
Kalhee Kim45fede42017-09-05 19:05:06 +000041import org.onlab.packet.Ip6Address;
42import org.onlab.packet.IpPrefix;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070043import org.onlab.packet.IpAddress;
44import org.onlab.packet.MacAddress;
45import org.onlab.packet.UDP;
46import org.onlab.packet.VlanId;
47import org.onlab.packet.dhcp.CircuitId;
48import org.onlab.packet.dhcp.DhcpOption;
49import org.onlab.packet.dhcp.DhcpRelayAgentOption;
Kalhee Kim45fede42017-09-05 19:05:06 +000050import org.onlab.packet.dhcp.Dhcp6InterfaceIdOption;
51import org.onlab.packet.dhcp.Dhcp6RelayOption;
52import org.onlab.packet.dhcp.Dhcp6IaNaOption;
53import org.onlab.packet.dhcp.Dhcp6IaPdOption;
54import org.onlab.packet.dhcp.Dhcp6IaAddressOption;
55import org.onlab.packet.dhcp.Dhcp6IaPrefixOption;
56import org.onlab.packet.dhcp.Dhcp6Option;
Kalhee Kim495c9b22017-11-07 16:32:09 +000057import org.onlab.packet.dhcp.Dhcp6ClientIdOption;
58import org.onlab.packet.dhcp.Dhcp6Duid;
Kalhee Kimd94ceea2017-11-29 19:03:02 +000059import org.onosproject.dhcprelay.store.DhcpRelayStore;
60import org.onosproject.dhcprelay.store.DhcpRecord;
61import org.onosproject.dhcprelay.store.DhcpRelayStoreEvent;
62import org.onosproject.dhcprelay.store.DhcpRelayCounters;
63import org.onosproject.dhcprelay.store.DhcpRelayCountersStore;
Kalhee Kim45fede42017-09-05 19:05:06 +000064import org.onosproject.net.ConnectPoint;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070065import org.onosproject.TestApplicationId;
66import org.onosproject.cfg.ComponentConfigService;
67import org.onosproject.core.ApplicationId;
68import org.onosproject.core.CoreService;
Yi Tseng483ac6f2017-08-02 15:03:31 -070069import org.onosproject.dhcprelay.config.DefaultDhcpRelayConfig;
70import org.onosproject.dhcprelay.config.DhcpServerConfig;
Yi Tseng51f1be92017-09-01 17:24:57 -070071import org.onosproject.dhcprelay.config.IgnoreDhcpConfig;
Yi Tseng483ac6f2017-08-02 15:03:31 -070072import org.onosproject.dhcprelay.config.IndirectDhcpRelayConfig;
Yi Tseng127ffe52017-09-12 15:55:17 -070073import org.onosproject.net.Device;
Yi Tseng51f1be92017-09-01 17:24:57 -070074import org.onosproject.net.DeviceId;
Yi Tseng127ffe52017-09-12 15:55:17 -070075import org.onosproject.net.behaviour.Pipeliner;
76import org.onosproject.net.device.DeviceEvent;
77import org.onosproject.net.device.DeviceService;
Yi Tseng51f1be92017-09-01 17:24:57 -070078import org.onosproject.net.flow.DefaultTrafficSelector;
79import org.onosproject.net.flow.DefaultTrafficTreatment;
80import org.onosproject.net.flow.TrafficSelector;
Yi Tseng51f1be92017-09-01 17:24:57 -070081import org.onosproject.net.flowobjective.FlowObjectiveService;
82import org.onosproject.net.flowobjective.ForwardingObjective;
83import org.onosproject.net.flowobjective.Objective;
Yi Tsengaa417a62017-09-08 17:22:51 -070084import org.onosproject.net.host.HostProviderService;
Ray Milkeyfacf2862017-08-03 11:58:29 -070085import org.onosproject.net.intf.Interface;
86import org.onosproject.net.intf.InterfaceServiceAdapter;
Yi Tseng51f1be92017-09-01 17:24:57 -070087import org.onosproject.net.packet.PacketPriority;
Ray Milkey69ec8712017-08-08 13:00:43 -070088import org.onosproject.routeservice.Route;
89import org.onosproject.routeservice.RouteStoreAdapter;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070090import org.onosproject.net.DefaultHost;
91import org.onosproject.net.Host;
92import org.onosproject.net.HostId;
93import org.onosproject.net.HostLocation;
94import org.onosproject.net.config.NetworkConfigRegistry;
95import org.onosproject.net.host.HostDescription;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070096import org.onosproject.net.host.HostService;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070097import org.onosproject.net.host.InterfaceIpAddress;
98import org.onosproject.net.packet.DefaultInboundPacket;
99import org.onosproject.net.packet.InboundPacket;
100import org.onosproject.net.packet.OutboundPacket;
101import org.onosproject.net.packet.PacketContext;
102import org.onosproject.net.packet.PacketContextAdapter;
103import org.onosproject.net.packet.PacketProcessor;
104import org.onosproject.net.packet.PacketServiceAdapter;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700105import org.onosproject.store.StoreDelegate;
Kalhee Kimba366062017-11-07 16:32:09 +0000106
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700107import org.osgi.service.component.ComponentContext;
Kalhee Kim45fede42017-09-05 19:05:06 +0000108import org.onlab.packet.DHCP6;
109import org.onlab.packet.IPv6;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700110
Yi Tseng127ffe52017-09-12 15:55:17 -0700111import java.io.IOException;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700112import java.nio.ByteBuffer;
113import java.util.Collection;
114import java.util.Dictionary;
115import java.util.List;
Kalhee Kim45fede42017-09-05 19:05:06 +0000116import java.util.ArrayList;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700117import java.util.Map;
118import java.util.Optional;
119import java.util.Set;
120import java.util.stream.Collectors;
121
122import static org.easymock.EasyMock.*;
123import static org.junit.Assert.*;
Ruchi Sahotae4934e12019-03-01 16:56:07 +0000124import static org.onlab.junit.TestTools.assertAfter;
Yi Tseng51f1be92017-09-01 17:24:57 -0700125import static org.onosproject.dhcprelay.DhcpRelayManager.DHCP_RELAY_APP;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700126
127public class DhcpRelayManagerTest {
Ruchi Sahotae4934e12019-03-01 16:56:07 +0000128 private static final int EVENT_PROCESSING_MS = 1000;
Charles Chan64a1c8e2019-01-23 15:03:17 -0800129 private static final int PKT_PROCESSING_MS = 500;
Kalhee Kima0b8f652017-10-18 22:00:30 +0000130 private static final short VLAN_LEN = 2;
131 private static final short SEPARATOR_LEN = 1;
Yi Tseng51f1be92017-09-01 17:24:57 -0700132 private static final String CONFIG_FILE_PATH = "dhcp-relay.json";
133 private static final DeviceId DEV_1_ID = DeviceId.deviceId("of:0000000000000001");
134 private static final DeviceId DEV_2_ID = DeviceId.deviceId("of:0000000000000002");
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700135 // Ip address for interfaces
136 private static final InterfaceIpAddress INTERFACE_IP = InterfaceIpAddress.valueOf("10.0.3.254/32");
Kalhee Kim45fede42017-09-05 19:05:06 +0000137 private static final InterfaceIpAddress INTERFACE_IP_V6 = InterfaceIpAddress.valueOf("2001:db8:1::254/128");
138 private static final List<InterfaceIpAddress> INTERFACE_IPS = ImmutableList.of(INTERFACE_IP, INTERFACE_IP_V6);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700139
140 // DHCP client (will send without option 82)
141 private static final Ip4Address IP_FOR_CLIENT = Ip4Address.valueOf("10.0.0.1");
Kalhee Kim45fede42017-09-05 19:05:06 +0000142 private static final Ip6Address IP_FOR_CLIENT_V6 = Ip6Address.valueOf("2001:db8:1::110");
143 private static final IpPrefix PREFIX_FOR_CLIENT_V6 = IpPrefix.valueOf("2001:db8:10::/56");
144 private static final IpPrefix PREFIX_FOR_ZERO = IpPrefix.valueOf("::/0");
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700145 private static final MacAddress CLIENT_MAC = MacAddress.valueOf("00:00:00:00:00:01");
146 private static final VlanId CLIENT_VLAN = VlanId.vlanId("100");
147 private static final ConnectPoint CLIENT_CP = ConnectPoint.deviceConnectPoint("of:0000000000000001/1");
148 private static final MacAddress CLIENT_IFACE_MAC = MacAddress.valueOf("00:00:00:00:11:01");
Yi Tsengaa417a62017-09-08 17:22:51 -0700149 private static final HostLocation CLIENT_LOCATION = new HostLocation(CLIENT_CP, 0);
150 private static final HostId CLIENT_HOST_ID = HostId.hostId(CLIENT_MAC, CLIENT_VLAN);
151 private static final Ip6Address CLIENT_LL_IP_V6 = Ip6Address.valueOf("fe80::200:00ff:fe00:0001");
Charles Chand988c282017-09-12 17:09:32 -0700152 private static final Host EXISTS_HOST = new DefaultHost(Dhcp4HandlerImpl.PROVIDER_ID,
Yi Tsengaa417a62017-09-08 17:22:51 -0700153 CLIENT_HOST_ID, CLIENT_MAC, CLIENT_VLAN,
154 CLIENT_LOCATION, ImmutableSet.of(CLIENT_LL_IP_V6));
Yi Tseng4025a102017-09-30 11:35:42 +0800155 private static final Interface CLIENT_INTERFACE = createInterface("C1",
156 CLIENT_CP,
157 INTERFACE_IPS,
158 CLIENT_IFACE_MAC,
159 CLIENT_VLAN,
160 null);
161
162
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700163
Yi Tsengaa417a62017-09-08 17:22:51 -0700164 // Dual homing test
165 private static final ConnectPoint CLIENT_DH_CP = ConnectPoint.deviceConnectPoint("of:0000000000000001/3");
166 private static final HostLocation CLIENT_DH_LOCATION = new HostLocation(CLIENT_DH_CP, 0);
Yi Tseng4025a102017-09-30 11:35:42 +0800167 private static final Interface CLIENT_DH_INTERFACE = createInterface("C1-DH",
168 CLIENT_DH_CP,
169 INTERFACE_IPS,
170 CLIENT_IFACE_MAC,
171 CLIENT_VLAN,
172 null);
Yi Tsengaa417a62017-09-08 17:22:51 -0700173
174
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700175 // DHCP client 2 (will send with option 82, so the vlan should equals to vlan from server)
176 private static final MacAddress CLIENT2_MAC = MacAddress.valueOf("00:00:00:00:00:01");
177 private static final VlanId CLIENT2_VLAN = VlanId.NONE;
Yi Tseng4025a102017-09-30 11:35:42 +0800178 private static final VlanId CLIENT2_VLAN_NATIVE = VlanId.vlanId("20");
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700179 private static final ConnectPoint CLIENT2_CP = ConnectPoint.deviceConnectPoint("of:0000000000000001/2");
180 private static final MacAddress CLIENT2_IFACE_MAC = MacAddress.valueOf("00:00:00:00:11:01");
Yi Tseng4025a102017-09-30 11:35:42 +0800181 private static final Interface CLIENT2_INTERFACE = createInterface("C2",
182 CLIENT2_CP,
183 INTERFACE_IPS,
184 CLIENT2_IFACE_MAC,
185 CLIENT2_VLAN,
186 CLIENT2_VLAN_NATIVE);
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000187 private static final VlanId CLIENT_BOGUS_VLAN = VlanId.vlanId("108");
188
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700189 // Outer relay information
Kalhee Kim121ba922017-11-01 17:56:44 +0000190 private static final Ip4Address OUTER_RELAY_IP = Ip4Address.valueOf("10.0.6.253");
Kalhee Kim45fede42017-09-05 19:05:06 +0000191 private static final Ip6Address OUTER_RELAY_IP_V6 = Ip6Address.valueOf("2001:db8:1::4");
Kalhee Kim121ba922017-11-01 17:56:44 +0000192 private static final Ip6Address OUTER_RELAY_LL_IP_V6 = Ip6Address.valueOf("fe80::200:0102:0304:0501");
193 private static final Set<IpAddress> OUTER_RELAY_IPS = ImmutableSet.of(OUTER_RELAY_IP,
194 OUTER_RELAY_IP_V6,
195 OUTER_RELAY_LL_IP_V6);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700196 private static final MacAddress OUTER_RELAY_MAC = MacAddress.valueOf("00:01:02:03:04:05");
197 private static final VlanId OUTER_RELAY_VLAN = VlanId.NONE;
198 private static final ConnectPoint OUTER_RELAY_CP = ConnectPoint.deviceConnectPoint("of:0000000000000001/2");
199 private static final HostLocation OUTER_REPLAY_HL = new HostLocation(OUTER_RELAY_CP, 0);
200 private static final HostId OUTER_RELAY_HOST_ID = HostId.hostId(OUTER_RELAY_MAC, OUTER_RELAY_VLAN);
Charles Chand988c282017-09-12 17:09:32 -0700201 private static final Host OUTER_RELAY_HOST = new DefaultHost(Dhcp4HandlerImpl.PROVIDER_ID,
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700202 OUTER_RELAY_HOST_ID,
203 OUTER_RELAY_MAC,
204 OUTER_RELAY_VLAN,
205 OUTER_REPLAY_HL,
206 OUTER_RELAY_IPS);
207
208 // DHCP Server
209 private static final MacAddress SERVER_MAC = MacAddress.valueOf("00:00:00:00:00:01");
210 private static final VlanId SERVER_VLAN = VlanId.NONE;
Yi Tseng4025a102017-09-30 11:35:42 +0800211 private static final VlanId SERVER_VLAN_NATIVE = VlanId.vlanId("10");
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700212 private static final ConnectPoint SERVER_CONNECT_POINT =
213 ConnectPoint.deviceConnectPoint("of:0000000000000001/5");
214 private static final HostLocation SERVER_LOCATION =
215 new HostLocation(SERVER_CONNECT_POINT, 0);
Kalhee Kim45fede42017-09-05 19:05:06 +0000216 private static final Ip4Address GATEWAY_IP = Ip4Address.valueOf("10.0.5.253");
217 private static final Ip6Address GATEWAY_IP_V6 = Ip6Address.valueOf("2000::105:253");
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700218 private static final Ip4Address SERVER_IP = Ip4Address.valueOf("10.0.3.253");
Kalhee Kim45fede42017-09-05 19:05:06 +0000219 private static final Ip6Address SERVER_IP_V6 = Ip6Address.valueOf("2000::103:253");
220 private static final Ip6Address SERVER_IP_V6_MCAST = Ip6Address.valueOf("ff02::1:2");
221 private static final Set<IpAddress> DHCP_SERVER_IPS = ImmutableSet.of(SERVER_IP, SERVER_IP_V6);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700222 private static final HostId SERVER_HOST_ID = HostId.hostId(SERVER_MAC, SERVER_VLAN);
Charles Chand988c282017-09-12 17:09:32 -0700223 private static final Host SERVER_HOST = new DefaultHost(Dhcp4HandlerImpl.PROVIDER_ID,
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700224 SERVER_HOST_ID,
225 SERVER_MAC,
226 SERVER_VLAN,
227 SERVER_LOCATION,
228 DHCP_SERVER_IPS);
229 private static final MacAddress SERVER_IFACE_MAC = MacAddress.valueOf("00:00:00:00:00:01");
Yi Tseng4025a102017-09-30 11:35:42 +0800230 private static final Interface SERVER_INTERFACE = createInterface("SERVER",
231 SERVER_CONNECT_POINT,
232 INTERFACE_IPS,
233 SERVER_IFACE_MAC,
234 SERVER_VLAN,
235 SERVER_VLAN_NATIVE);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700236
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700237 // Relay agent config
238 private static final Ip4Address RELAY_AGENT_IP = Ip4Address.valueOf("10.0.4.254");
239
Yi Tseng525ff402017-10-23 19:39:39 -0700240 private static final List<TrafficSelector> DHCP_SELECTORS = buildClientDhcpSelectors();
241
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700242 // Components
243 private static final ApplicationId APP_ID = TestApplicationId.create(DhcpRelayManager.DHCP_RELAY_APP);
Yi Tseng483ac6f2017-08-02 15:03:31 -0700244 private static final DefaultDhcpRelayConfig CONFIG = new MockDefaultDhcpRelayConfig();
Kalhee Kim45fede42017-09-05 19:05:06 +0000245 private static final IndirectDhcpRelayConfig CONFIG_INDIRECT = new MockIndirectDhcpRelayConfig();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700246 private static final Set<Interface> INTERFACES = ImmutableSet.of(
247 CLIENT_INTERFACE,
248 CLIENT2_INTERFACE,
Yi Tsengaa417a62017-09-08 17:22:51 -0700249 SERVER_INTERFACE,
250 CLIENT_DH_INTERFACE
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700251 );
Yi Tseng440e2b72017-08-24 14:47:34 -0700252 private static final String NON_ONOS_CID = "Non-ONOS circuit ID";
Yi Tseng51f1be92017-09-01 17:24:57 -0700253 private static final VlanId IGNORED_VLAN = VlanId.vlanId("100");
254 private static final int IGNORE_CONTROL_PRIORITY = PacketPriority.CONTROL.priorityValue() + 1000;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700255
256 private DhcpRelayManager manager;
257 private MockPacketService packetService;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700258 private MockRouteStore mockRouteStore;
259 private MockDhcpRelayStore mockDhcpRelayStore;
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000260 private MockDhcpRelayCountersStore mockDhcpRelayCountersStore;
Yi Tsengaa417a62017-09-08 17:22:51 -0700261 private HostProviderService mockHostProviderService;
Yi Tseng525ff402017-10-23 19:39:39 -0700262 private FlowObjectiveService flowObjectiveService;
263 private DeviceService deviceService;
264 private Dhcp4HandlerImpl v4Handler;
265 private Dhcp6HandlerImpl v6Handler;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700266
Yi Tseng4025a102017-09-30 11:35:42 +0800267 private static Interface createInterface(String name, ConnectPoint connectPoint,
268 List<InterfaceIpAddress> interfaceIps,
269 MacAddress macAddress,
270 VlanId vlanId,
271 VlanId vlanNative) {
272
273 if (vlanId.equals(VlanId.NONE)) {
274 return new Interface(name, connectPoint, interfaceIps, macAddress, vlanId,
275 null, null, vlanNative);
276 } else {
277 return new Interface(name, connectPoint, interfaceIps, macAddress, vlanId,
278 null, ImmutableSet.of(vlanId), null);
279 }
280 }
281
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700282 @Before
283 public void setup() {
284 manager = new DhcpRelayManager();
285 manager.cfgService = createNiceMock(NetworkConfigRegistry.class);
286
Yi Tseng483ac6f2017-08-02 15:03:31 -0700287 expect(manager.cfgService.getConfig(APP_ID, DefaultDhcpRelayConfig.class))
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700288 .andReturn(CONFIG)
289 .anyTimes();
290
Yi Tseng483ac6f2017-08-02 15:03:31 -0700291 expect(manager.cfgService.getConfig(APP_ID, IndirectDhcpRelayConfig.class))
Kalhee Kim45fede42017-09-05 19:05:06 +0000292 .andReturn(CONFIG_INDIRECT)
Yi Tseng483ac6f2017-08-02 15:03:31 -0700293 .anyTimes();
294
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700295 manager.coreService = createNiceMock(CoreService.class);
296 expect(manager.coreService.registerApplication(anyString()))
297 .andReturn(APP_ID).anyTimes();
298
299 manager.hostService = createNiceMock(HostService.class);
Kalhee Kim121ba922017-11-01 17:56:44 +0000300
301 expect(manager.hostService.getHostsByIp(OUTER_RELAY_IP_V6))
302 .andReturn(ImmutableSet.of(OUTER_RELAY_HOST)).anyTimes();
303 expect(manager.hostService.getHostsByIp(SERVER_IP))
304 .andReturn(ImmutableSet.of(SERVER_HOST)).anyTimes();
305 expect(manager.hostService.getHostsByIp(SERVER_IP_V6))
306 .andReturn(ImmutableSet.of(SERVER_HOST)).anyTimes();
307 expect(manager.hostService.getHostsByIp(GATEWAY_IP))
308 .andReturn(ImmutableSet.of(SERVER_HOST)).anyTimes();
309 expect(manager.hostService.getHostsByIp(GATEWAY_IP_V6))
310 .andReturn(ImmutableSet.of(SERVER_HOST)).anyTimes();
311 expect(manager.hostService.getHostsByIp(CLIENT_LL_IP_V6))
312 .andReturn(ImmutableSet.of(EXISTS_HOST)).anyTimes();
313
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700314 expect(manager.hostService.getHost(OUTER_RELAY_HOST_ID)).andReturn(OUTER_RELAY_HOST).anyTimes();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700315
316 packetService = new MockPacketService();
317 manager.packetService = packetService;
318 manager.compCfgService = createNiceMock(ComponentConfigService.class);
Yi Tseng525ff402017-10-23 19:39:39 -0700319 deviceService = createNiceMock(DeviceService.class);
Yi Tseng127ffe52017-09-12 15:55:17 -0700320
321 Device device = createNiceMock(Device.class);
322 expect(device.is(Pipeliner.class)).andReturn(true).anyTimes();
323
Yi Tseng525ff402017-10-23 19:39:39 -0700324 expect(deviceService.getDevice(DEV_1_ID)).andReturn(device).anyTimes();
325 expect(deviceService.getDevice(DEV_2_ID)).andReturn(device).anyTimes();
326 replay(deviceService, device);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700327
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700328 mockRouteStore = new MockRouteStore();
329 mockDhcpRelayStore = new MockDhcpRelayStore();
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000330 mockDhcpRelayCountersStore = new MockDhcpRelayCountersStore();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700331
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000332 manager.dhcpRelayStore = mockDhcpRelayStore;
333
334 manager.deviceService = deviceService;
Kalhee Kimba366062017-11-07 16:32:09 +0000335
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700336 manager.interfaceService = new MockInterfaceService();
Yi Tseng525ff402017-10-23 19:39:39 -0700337 flowObjectiveService = EasyMock.niceMock(FlowObjectiveService.class);
Yi Tsengaa417a62017-09-08 17:22:51 -0700338 mockHostProviderService = createNiceMock(HostProviderService.class);
Yi Tseng525ff402017-10-23 19:39:39 -0700339 v4Handler = new Dhcp4HandlerImpl();
Yi Tsengaa417a62017-09-08 17:22:51 -0700340 v4Handler.providerService = mockHostProviderService;
Yi Tseng51301292017-07-28 13:02:59 -0700341 v4Handler.dhcpRelayStore = mockDhcpRelayStore;
342 v4Handler.hostService = manager.hostService;
Yi Tseng51301292017-07-28 13:02:59 -0700343 v4Handler.interfaceService = manager.interfaceService;
344 v4Handler.packetService = manager.packetService;
345 v4Handler.routeStore = mockRouteStore;
Yi Tseng525ff402017-10-23 19:39:39 -0700346 v4Handler.coreService = createNiceMock(CoreService.class);
347 v4Handler.flowObjectiveService = flowObjectiveService;
348 v4Handler.appId = TestApplicationId.create(Dhcp4HandlerImpl.DHCP_V4_RELAY_APP);
349 v4Handler.deviceService = deviceService;
Yi Tseng51301292017-07-28 13:02:59 -0700350 manager.v4Handler = v4Handler;
351
Yi Tseng525ff402017-10-23 19:39:39 -0700352 v6Handler = new Dhcp6HandlerImpl();
Kalhee Kim45fede42017-09-05 19:05:06 +0000353 v6Handler.dhcpRelayStore = mockDhcpRelayStore;
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000354 v6Handler.dhcpRelayCountersStore = mockDhcpRelayCountersStore;
Kalhee Kim45fede42017-09-05 19:05:06 +0000355 v6Handler.hostService = manager.hostService;
Kalhee Kim45fede42017-09-05 19:05:06 +0000356 v6Handler.interfaceService = manager.interfaceService;
357 v6Handler.packetService = manager.packetService;
358 v6Handler.routeStore = mockRouteStore;
Yi Tsengaa417a62017-09-08 17:22:51 -0700359 v6Handler.providerService = mockHostProviderService;
Yi Tseng525ff402017-10-23 19:39:39 -0700360 v6Handler.coreService = createNiceMock(CoreService.class);
361 v6Handler.flowObjectiveService = flowObjectiveService;
362 v6Handler.appId = TestApplicationId.create(Dhcp6HandlerImpl.DHCP_V6_RELAY_APP);
363 v6Handler.deviceService = deviceService;
Yi Tseng483ac6f2017-08-02 15:03:31 -0700364 manager.v6Handler = v6Handler;
365
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700366 // properties
367 Dictionary<String, Object> dictionary = createNiceMock(Dictionary.class);
368 expect(dictionary.get("arpEnabled")).andReturn(true).anyTimes();
Kalhee Kim495c9b22017-11-07 16:32:09 +0000369 expect(dictionary.get("dhcpPollInterval")).andReturn(120).anyTimes();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700370 ComponentContext context = createNiceMock(ComponentContext.class);
371 expect(context.getProperties()).andReturn(dictionary).anyTimes();
372
Yi Tseng4025a102017-09-30 11:35:42 +0800373 replay(manager.cfgService, manager.coreService, manager.hostService,
374 manager.compCfgService, dictionary, context);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700375 manager.activate(context);
376 }
377
378 @After
379 public void tearDown() {
380 manager.deactivate();
381 }
382
383 /**
384 * Relay a DHCP packet without option 82.
385 * Should add new host to host store after dhcp ack.
386 */
387 @Test
388 public void relayDhcpWithoutAgentInfo() {
Yi Tsengaa417a62017-09-08 17:22:51 -0700389 replay(mockHostProviderService);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700390 // send request
391 packetService.processPacket(new TestDhcpRequestPacketContext(CLIENT_MAC,
392 CLIENT_VLAN,
393 CLIENT_CP,
394 INTERFACE_IP.ipAddress().getIp4Address(),
395 false));
Yi Tsengaa417a62017-09-08 17:22:51 -0700396 // won't trigger the host provider service
397 verify(mockHostProviderService);
398 reset(mockHostProviderService);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700399
Charles Chan64a1c8e2019-01-23 15:03:17 -0800400 assertAfter(PKT_PROCESSING_MS, () -> assertEquals(0, mockRouteStore.routes.size()));
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700401
Yi Tsengaa417a62017-09-08 17:22:51 -0700402 HostId expectHostId = HostId.hostId(CLIENT_MAC, CLIENT_VLAN);
403 Capture<HostDescription> capturedHostDesc = newCapture();
404 mockHostProviderService.hostDetected(eq(expectHostId), capture(capturedHostDesc), eq(false));
405 replay(mockHostProviderService);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700406 // send ack
407 packetService.processPacket(new TestDhcpAckPacketContext(CLIENT_CP, CLIENT_MAC,
408 CLIENT_VLAN, INTERFACE_IP.ipAddress().getIp4Address(),
409 false));
Charles Chan64a1c8e2019-01-23 15:03:17 -0800410 assertAfter(PKT_PROCESSING_MS, () -> verify(mockHostProviderService));
411 assertAfter(PKT_PROCESSING_MS, () -> assertEquals(0, mockRouteStore.routes.size()));
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700412
Yi Tsengaa417a62017-09-08 17:22:51 -0700413 HostDescription host = capturedHostDesc.getValue();
Charles Chan64a1c8e2019-01-23 15:03:17 -0800414 assertAfter(PKT_PROCESSING_MS, () -> assertFalse(host.configured()));
415 assertAfter(PKT_PROCESSING_MS, () -> assertEquals(CLIENT_CP.deviceId(), host.location().elementId()));
416 assertAfter(PKT_PROCESSING_MS, () -> assertEquals(CLIENT_CP.port(), host.location().port()));
417 assertAfter(PKT_PROCESSING_MS, () -> assertEquals(1, host.ipAddress().size()));
418 assertAfter(PKT_PROCESSING_MS, () -> assertEquals(IP_FOR_CLIENT, host.ipAddress().iterator().next()));
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700419 }
420
421 /**
422 * Relay a DHCP packet with option 82 (Indirectly connected host).
423 */
424 @Test
425 public void relayDhcpWithAgentInfo() {
Yi Tsengaa417a62017-09-08 17:22:51 -0700426 replay(mockHostProviderService);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700427 // Assume outer dhcp relay agent exists in store already
428 // send request
429 packetService.processPacket(new TestDhcpRequestPacketContext(CLIENT2_MAC,
Charles Chan64a1c8e2019-01-23 15:03:17 -0800430 CLIENT2_VLAN,
431 CLIENT2_CP,
432 INTERFACE_IP.ipAddress().getIp4Address(),
433 true));
Yi Tsengaa417a62017-09-08 17:22:51 -0700434 // No routes
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700435 assertEquals(0, mockRouteStore.routes.size());
Charles Chan64a1c8e2019-01-23 15:03:17 -0800436
437 // Make sure the REQUEST packet has been processed before start sending ACK
438 assertAfter(PKT_PROCESSING_MS, () -> assertNotNull(packetService.emittedPacket));
439
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700440 // send ack
441 packetService.processPacket(new TestDhcpAckPacketContext(CLIENT2_CP,
442 CLIENT2_MAC,
443 CLIENT2_VLAN,
444 INTERFACE_IP.ipAddress().getIp4Address(),
445 true));
446
Yi Tsengaa417a62017-09-08 17:22:51 -0700447 // won't trigger the host provider service
448 verify(mockHostProviderService);
449 reset(mockHostProviderService);
Charles Chan64a1c8e2019-01-23 15:03:17 -0800450 assertAfter(PKT_PROCESSING_MS, () -> assertEquals(1, mockRouteStore.routes.size()));
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700451
452 Route route = mockRouteStore.routes.get(0);
Charles Chan64a1c8e2019-01-23 15:03:17 -0800453 assertAfter(PKT_PROCESSING_MS, () -> assertEquals(OUTER_RELAY_IP, route.nextHop()));
454 assertAfter(PKT_PROCESSING_MS, () -> assertEquals(IP_FOR_CLIENT.toIpPrefix(), route.prefix()));
455 assertAfter(PKT_PROCESSING_MS, () -> assertEquals(Route.Source.DHCP, route.source()));
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700456 }
457
458 @Test
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700459 public void testWithRelayAgentConfig() throws DeserializationException {
460 manager.v4Handler
461 .setDefaultDhcpServerConfigs(ImmutableList.of(new MockDhcpServerConfig(RELAY_AGENT_IP)));
Yi Tseng4f2a0462017-08-31 11:21:00 -0700462 manager.v4Handler
463 .setIndirectDhcpServerConfigs(ImmutableList.of(new MockDhcpServerConfig(RELAY_AGENT_IP)));
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700464 packetService.processPacket(new TestDhcpRequestPacketContext(CLIENT2_MAC,
465 CLIENT2_VLAN,
466 CLIENT2_CP,
467 INTERFACE_IP.ipAddress().getIp4Address(),
468 true));
Charles Chan64a1c8e2019-01-23 15:03:17 -0800469 assertAfter(PKT_PROCESSING_MS, () -> assertNotNull(packetService.emittedPacket));
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700470 OutboundPacket outPacket = packetService.emittedPacket;
471 byte[] outData = outPacket.data().array();
472 Ethernet eth = Ethernet.deserializer().deserialize(outData, 0, outData.length);
473 IPv4 ip = (IPv4) eth.getPayload();
474 UDP udp = (UDP) ip.getPayload();
475 DHCP dhcp = (DHCP) udp.getPayload();
Charles Chan64a1c8e2019-01-23 15:03:17 -0800476 assertAfter(PKT_PROCESSING_MS, () -> assertEquals(RELAY_AGENT_IP.toInt(), dhcp.getGatewayIPAddress()));
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700477 }
478
479 @Test
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700480 public void testArpRequest() throws Exception {
481 packetService.processPacket(new TestArpRequestPacketContext(CLIENT_INTERFACE));
Charles Chan64a1c8e2019-01-23 15:03:17 -0800482 assertAfter(PKT_PROCESSING_MS, () -> assertNotNull(packetService.emittedPacket));
Ray Milkeyc108a6b2017-08-23 15:23:50 -0700483 OutboundPacket outboundPacket = packetService.emittedPacket;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700484 byte[] outPacketData = outboundPacket.data().array();
485 Ethernet eth = Ethernet.deserializer().deserialize(outPacketData, 0, outPacketData.length);
486
Charles Chan64a1c8e2019-01-23 15:03:17 -0800487 assertAfter(PKT_PROCESSING_MS, () -> assertEquals(eth.getEtherType(), Ethernet.TYPE_ARP));
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700488 ARP arp = (ARP) eth.getPayload();
Charles Chan64a1c8e2019-01-23 15:03:17 -0800489 assertAfter(PKT_PROCESSING_MS, () ->
490 assertArrayEquals(arp.getSenderHardwareAddress(), CLIENT_INTERFACE.mac().toBytes()));
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700491 }
492
Yi Tseng51f1be92017-09-01 17:24:57 -0700493 /**
494 * Ignores specific vlans from specific devices if config.
495 *
496 * @throws Exception the exception from this test
497 */
498 @Test
499 public void testIgnoreVlan() throws Exception {
500 ObjectMapper om = new ObjectMapper();
501 JsonNode json = om.readTree(Resources.getResource(CONFIG_FILE_PATH));
502 IgnoreDhcpConfig config = new IgnoreDhcpConfig();
503 json = json.path("apps").path(DHCP_RELAY_APP).path(IgnoreDhcpConfig.KEY);
504 config.init(APP_ID, IgnoreDhcpConfig.KEY, json, om, null);
505
506 Capture<Objective> capturedFromDev1 = newCapture(CaptureType.ALL);
Yi Tseng525ff402017-10-23 19:39:39 -0700507 flowObjectiveService.apply(eq(DEV_1_ID), capture(capturedFromDev1));
Yi Tseng127ffe52017-09-12 15:55:17 -0700508 expectLastCall().times(DHCP_SELECTORS.size());
Yi Tseng51f1be92017-09-01 17:24:57 -0700509 Capture<Objective> capturedFromDev2 = newCapture(CaptureType.ALL);
Yi Tseng525ff402017-10-23 19:39:39 -0700510 flowObjectiveService.apply(eq(DEV_2_ID), capture(capturedFromDev2));
Yi Tseng127ffe52017-09-12 15:55:17 -0700511 expectLastCall().times(DHCP_SELECTORS.size());
Yi Tseng525ff402017-10-23 19:39:39 -0700512 replay(flowObjectiveService);
Yi Tseng51f1be92017-09-01 17:24:57 -0700513 manager.updateConfig(config);
Yi Tseng525ff402017-10-23 19:39:39 -0700514 verify(flowObjectiveService);
Yi Tseng51f1be92017-09-01 17:24:57 -0700515
516 List<Objective> objectivesFromDev1 = capturedFromDev1.getValues();
517 List<Objective> objectivesFromDev2 = capturedFromDev2.getValues();
518
519 assertTrue(objectivesFromDev1.containsAll(objectivesFromDev2));
520 assertTrue(objectivesFromDev2.containsAll(objectivesFromDev1));
Yi Tseng51f1be92017-09-01 17:24:57 -0700521
522 for (int index = 0; index < objectivesFromDev1.size(); index++) {
523 TrafficSelector selector =
Yi Tseng525ff402017-10-23 19:39:39 -0700524 DefaultTrafficSelector.builder(DHCP_SELECTORS.get(index))
Yi Tseng51f1be92017-09-01 17:24:57 -0700525 .matchVlanId(IGNORED_VLAN)
526 .build();
527 ForwardingObjective fwd = (ForwardingObjective) objectivesFromDev1.get(index);
528 assertEquals(selector, fwd.selector());
Yi Tsengdbabeed2017-11-29 10:49:20 -0800529 assertEquals(DefaultTrafficTreatment.emptyTreatment(), fwd.treatment());
Yi Tseng51f1be92017-09-01 17:24:57 -0700530 assertEquals(IGNORE_CONTROL_PRIORITY, fwd.priority());
531 assertEquals(ForwardingObjective.Flag.VERSATILE, fwd.flag());
532 assertEquals(Objective.Operation.ADD, fwd.op());
Yi Tseng127ffe52017-09-12 15:55:17 -0700533 fwd.context().ifPresent(ctx -> {
534 ctx.onSuccess(fwd);
535 });
Yi Tseng51f1be92017-09-01 17:24:57 -0700536 }
Yi Tseng127ffe52017-09-12 15:55:17 -0700537 objectivesFromDev2.forEach(obj -> obj.context().ifPresent(ctx -> ctx.onSuccess(obj)));
Yi Tseng525ff402017-10-23 19:39:39 -0700538 assertEquals(2, v4Handler.ignoredVlans.size());
539 assertEquals(2, v6Handler.ignoredVlans.size());
Yi Tseng51f1be92017-09-01 17:24:57 -0700540 }
541
542 /**
543 * "IgnoreVlan" policy should be removed when the config removed.
544 */
545 @Test
546 public void testRemoveIgnoreVlan() {
Yi Tseng525ff402017-10-23 19:39:39 -0700547 v4Handler.ignoredVlans.put(DEV_1_ID, IGNORED_VLAN);
548 v4Handler.ignoredVlans.put(DEV_2_ID, IGNORED_VLAN);
549 v6Handler.ignoredVlans.put(DEV_1_ID, IGNORED_VLAN);
550 v6Handler.ignoredVlans.put(DEV_2_ID, IGNORED_VLAN);
Yi Tseng51f1be92017-09-01 17:24:57 -0700551 IgnoreDhcpConfig config = new IgnoreDhcpConfig();
552
553 Capture<Objective> capturedFromDev1 = newCapture(CaptureType.ALL);
Yi Tseng525ff402017-10-23 19:39:39 -0700554 flowObjectiveService.apply(eq(DEV_1_ID), capture(capturedFromDev1));
Yi Tseng127ffe52017-09-12 15:55:17 -0700555 expectLastCall().times(DHCP_SELECTORS.size());
Yi Tseng51f1be92017-09-01 17:24:57 -0700556 Capture<Objective> capturedFromDev2 = newCapture(CaptureType.ALL);
Yi Tseng525ff402017-10-23 19:39:39 -0700557 flowObjectiveService.apply(eq(DEV_2_ID), capture(capturedFromDev2));
Yi Tseng127ffe52017-09-12 15:55:17 -0700558 expectLastCall().times(DHCP_SELECTORS.size());
Yi Tseng525ff402017-10-23 19:39:39 -0700559 replay(flowObjectiveService);
Yi Tseng51f1be92017-09-01 17:24:57 -0700560 manager.removeConfig(config);
Yi Tseng525ff402017-10-23 19:39:39 -0700561 verify(flowObjectiveService);
Yi Tseng51f1be92017-09-01 17:24:57 -0700562
563 List<Objective> objectivesFromDev1 = capturedFromDev1.getValues();
564 List<Objective> objectivesFromDev2 = capturedFromDev2.getValues();
565
566 assertTrue(objectivesFromDev1.containsAll(objectivesFromDev2));
567 assertTrue(objectivesFromDev2.containsAll(objectivesFromDev1));
Yi Tseng51f1be92017-09-01 17:24:57 -0700568
569 for (int index = 0; index < objectivesFromDev1.size(); index++) {
570 TrafficSelector selector =
Yi Tseng525ff402017-10-23 19:39:39 -0700571 DefaultTrafficSelector.builder(DHCP_SELECTORS.get(index))
Yi Tseng51f1be92017-09-01 17:24:57 -0700572 .matchVlanId(IGNORED_VLAN)
573 .build();
574 ForwardingObjective fwd = (ForwardingObjective) objectivesFromDev1.get(index);
575 assertEquals(selector, fwd.selector());
Yi Tsengdbabeed2017-11-29 10:49:20 -0800576 assertEquals(DefaultTrafficTreatment.emptyTreatment(), fwd.treatment());
Yi Tseng51f1be92017-09-01 17:24:57 -0700577 assertEquals(IGNORE_CONTROL_PRIORITY, fwd.priority());
578 assertEquals(ForwardingObjective.Flag.VERSATILE, fwd.flag());
579 assertEquals(Objective.Operation.REMOVE, fwd.op());
Yi Tseng127ffe52017-09-12 15:55:17 -0700580 fwd.context().ifPresent(ctx -> {
581 ctx.onSuccess(fwd);
582 });
Yi Tseng51f1be92017-09-01 17:24:57 -0700583 }
Yi Tseng127ffe52017-09-12 15:55:17 -0700584 objectivesFromDev2.forEach(obj -> obj.context().ifPresent(ctx -> ctx.onSuccess(obj)));
Yi Tseng525ff402017-10-23 19:39:39 -0700585 assertEquals(0, v4Handler.ignoredVlans.size());
586 assertEquals(0, v6Handler.ignoredVlans.size());
Yi Tseng51f1be92017-09-01 17:24:57 -0700587 }
588
Kalhee Kim45fede42017-09-05 19:05:06 +0000589 /**
Yi Tseng127ffe52017-09-12 15:55:17 -0700590 * Should ignore ignore rules installation when device not available.
591 */
592 @Test
593 public void testIgnoreUnknownDevice() throws IOException {
594 reset(manager.deviceService);
595 Device device = createNiceMock(Device.class);
596 expect(device.is(Pipeliner.class)).andReturn(true).anyTimes();
597
598 expect(manager.deviceService.getDevice(DEV_1_ID)).andReturn(device).anyTimes();
599 expect(manager.deviceService.getDevice(DEV_2_ID)).andReturn(null).anyTimes();
600
601 ObjectMapper om = new ObjectMapper();
602 JsonNode json = om.readTree(Resources.getResource(CONFIG_FILE_PATH));
603 IgnoreDhcpConfig config = new IgnoreDhcpConfig();
604 json = json.path("apps").path(DHCP_RELAY_APP).path(IgnoreDhcpConfig.KEY);
605 config.init(APP_ID, IgnoreDhcpConfig.KEY, json, om, null);
606
607 Capture<Objective> capturedFromDev1 = newCapture(CaptureType.ALL);
Yi Tseng525ff402017-10-23 19:39:39 -0700608 flowObjectiveService.apply(eq(DEV_1_ID), capture(capturedFromDev1));
Yi Tseng127ffe52017-09-12 15:55:17 -0700609 expectLastCall().times(DHCP_SELECTORS.size());
Yi Tseng525ff402017-10-23 19:39:39 -0700610 replay(flowObjectiveService, manager.deviceService, device);
Yi Tseng127ffe52017-09-12 15:55:17 -0700611
612 manager.updateConfig(config);
613 capturedFromDev1.getValues().forEach(obj -> obj.context().ifPresent(ctx -> ctx.onSuccess(obj)));
614
Yi Tseng525ff402017-10-23 19:39:39 -0700615 assertEquals(1, v4Handler.ignoredVlans.size());
616 assertEquals(1, v6Handler.ignoredVlans.size());
Yi Tseng127ffe52017-09-12 15:55:17 -0700617 }
618
619 /**
620 * Should try install ignore rules when device comes up.
621 */
622 @Test
623 public void testInstallIgnoreRuleWhenDeviceComesUp() throws IOException {
624 ObjectMapper om = new ObjectMapper();
625 JsonNode json = om.readTree(Resources.getResource(CONFIG_FILE_PATH));
626 IgnoreDhcpConfig config = new IgnoreDhcpConfig();
627 json = json.path("apps").path(DHCP_RELAY_APP).path(IgnoreDhcpConfig.KEY);
628 config.init(APP_ID, IgnoreDhcpConfig.KEY, json, om, null);
629
Yi Tseng525ff402017-10-23 19:39:39 -0700630 reset(manager.cfgService, flowObjectiveService, manager.deviceService);
Yi Tseng127ffe52017-09-12 15:55:17 -0700631 expect(manager.cfgService.getConfig(APP_ID, IgnoreDhcpConfig.class))
632 .andReturn(config).anyTimes();
633
634 Device device = createNiceMock(Device.class);
635 expect(device.is(Pipeliner.class)).andReturn(true).anyTimes();
636 expect(device.id()).andReturn(DEV_1_ID).anyTimes();
637 expect(manager.deviceService.getDevice(DEV_1_ID)).andReturn(device).anyTimes();
638 DeviceEvent event = new DeviceEvent(DeviceEvent.Type.DEVICE_ADDED, device);
639 Capture<Objective> capturedFromDev1 = newCapture(CaptureType.ALL);
Yi Tseng525ff402017-10-23 19:39:39 -0700640 flowObjectiveService.apply(eq(DEV_1_ID), capture(capturedFromDev1));
Yi Tseng127ffe52017-09-12 15:55:17 -0700641 expectLastCall().times(DHCP_SELECTORS.size());
Yi Tseng525ff402017-10-23 19:39:39 -0700642 replay(manager.cfgService, flowObjectiveService, manager.deviceService, device);
Ruchi Sahotae4934e12019-03-01 16:56:07 +0000643
Yi Tseng127ffe52017-09-12 15:55:17 -0700644 manager.deviceListener.event(event);
Ruchi Sahotae4934e12019-03-01 16:56:07 +0000645
646 // Wait until all flow objective events are captured before triggering onSuccess
647 int expectFlowObjCount = Dhcp4HandlerImpl.DHCP_SELECTORS.size() + Dhcp6HandlerImpl.DHCP_SELECTORS.size();
648 assertAfter(EVENT_PROCESSING_MS, () -> assertEquals(expectFlowObjCount, capturedFromDev1.getValues().size()));
Yi Tseng127ffe52017-09-12 15:55:17 -0700649 capturedFromDev1.getValues().forEach(obj -> obj.context().ifPresent(ctx -> ctx.onSuccess(obj)));
Ruchi Sahotae4934e12019-03-01 16:56:07 +0000650
651 assertAfter(EVENT_PROCESSING_MS, () -> assertEquals(1, v4Handler.ignoredVlans.size()));
652 assertAfter(EVENT_PROCESSING_MS, () -> assertEquals(1, v6Handler.ignoredVlans.size()));
Yi Tseng127ffe52017-09-12 15:55:17 -0700653 }
654
655 /**
Kalhee Kim45fede42017-09-05 19:05:06 +0000656 * Relay a DHCP6 packet without relay option
657 * Note: Should add new host to host store after dhcp ack.
658 */
659 @Test
660 public void relayDhcp6WithoutAgentInfo() {
Yi Tsengaa417a62017-09-08 17:22:51 -0700661 replay(mockHostProviderService);
Kalhee Kim45fede42017-09-05 19:05:06 +0000662 // send request
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000663 packetService.processPacket(new TestDhcp6RequestPacketContext(DHCP6.MsgType.REQUEST.value(),
664 CLIENT_MAC,
665 CLIENT_VLAN,
Kalhee Kim45fede42017-09-05 19:05:06 +0000666 CLIENT_CP,
667 INTERFACE_IP_V6.ipAddress().getIp6Address(),
668 0));
669
Yi Tsengaa417a62017-09-08 17:22:51 -0700670 verify(mockHostProviderService);
671 reset(mockHostProviderService);
Charles Chan64a1c8e2019-01-23 15:03:17 -0800672 assertAfter(PKT_PROCESSING_MS, () -> assertEquals(0, mockRouteStore.routes.size()));
Kalhee Kim45fede42017-09-05 19:05:06 +0000673
Yi Tsengaa417a62017-09-08 17:22:51 -0700674 Capture<HostDescription> capturedHostDesc = newCapture();
675 mockHostProviderService.hostDetected(eq(HostId.hostId(CLIENT_MAC, CLIENT_VLAN)),
676 capture(capturedHostDesc), eq(false));
677 replay(mockHostProviderService);
Kalhee Kim45fede42017-09-05 19:05:06 +0000678 // send reply
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000679 packetService.processPacket(new TestDhcp6ReplyPacketContext(DHCP6.MsgType.REPLY.value(),
680 CLIENT_CP, CLIENT_MAC,
Kalhee Kim45fede42017-09-05 19:05:06 +0000681 CLIENT_VLAN,
682 INTERFACE_IP_V6.ipAddress().getIp6Address(),
Kalhee Kim121ba922017-11-01 17:56:44 +0000683 0, false, CLIENT_VLAN));
Charles Chan64a1c8e2019-01-23 15:03:17 -0800684 assertAfter(PKT_PROCESSING_MS, () -> verify(mockHostProviderService));
685 assertAfter(PKT_PROCESSING_MS, () -> assertEquals(0, mockRouteStore.routes.size()));
Kalhee Kim45fede42017-09-05 19:05:06 +0000686
Yi Tsengaa417a62017-09-08 17:22:51 -0700687 HostDescription host = capturedHostDesc.getValue();
Charles Chan64a1c8e2019-01-23 15:03:17 -0800688 assertAfter(PKT_PROCESSING_MS, () -> assertEquals(CLIENT_VLAN, host.vlan()));
689 assertAfter(PKT_PROCESSING_MS, () -> assertEquals(CLIENT_CP.deviceId(), host.location().elementId()));
690 assertAfter(PKT_PROCESSING_MS, () -> assertEquals(CLIENT_CP.port(), host.location().port()));
691 assertAfter(PKT_PROCESSING_MS, () -> assertEquals(1, host.ipAddress().size()));
692 assertAfter(PKT_PROCESSING_MS, () -> assertEquals(IP_FOR_CLIENT_V6, host.ipAddress().iterator().next()));
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000693
694 // send release
695 packetService.processPacket(new TestDhcp6RequestPacketContext(DHCP6.MsgType.RELEASE.value(),
696 CLIENT_MAC,
697 CLIENT_VLAN,
698 CLIENT_CP,
699 INTERFACE_IP_V6.ipAddress().getIp6Address(),
700 0));
701
Charles Chan64a1c8e2019-01-23 15:03:17 -0800702 assertAfter(PKT_PROCESSING_MS,
703 () -> assertNull(manager.hostService.getHost(HostId.hostId(CLIENT_MAC, CLIENT_VLAN))));
Kalhee Kim45fede42017-09-05 19:05:06 +0000704 }
705
706 /**
707 * Relay a DHCP6 packet with Relay Message opion (Indirectly connected host).
708 */
709 @Test
710 public void relayDhcp6WithAgentInfo() {
Yi Tsengaa417a62017-09-08 17:22:51 -0700711 replay(mockHostProviderService);
Kalhee Kim45fede42017-09-05 19:05:06 +0000712 // Assume outer dhcp6 relay agent exists in store already
713 // send request
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000714 packetService.processPacket(new TestDhcp6RequestPacketContext(DHCP6.MsgType.REQUEST.value(),
715 CLIENT2_MAC,
716 CLIENT2_VLAN,
717 CLIENT2_CP,
718 OUTER_RELAY_IP_V6,
719 1));
720
721 assertEquals(0, mockRouteStore.routes.size());
722
Charles Chan64a1c8e2019-01-23 15:03:17 -0800723 // Make sure the REQUEST packet has been processed before start sending ACK
724 assertAfter(PKT_PROCESSING_MS, () -> assertNotNull(packetService.emittedPacket));
725
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000726 // send reply
727 packetService.processPacket(new TestDhcp6ReplyPacketContext(DHCP6.MsgType.REPLY.value(), CLIENT2_CP,
728 CLIENT2_MAC,
729 CLIENT2_VLAN,
730 OUTER_RELAY_IP_V6,
Kalhee Kim121ba922017-11-01 17:56:44 +0000731 1, false, CLIENT2_VLAN));
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000732
733 // won't trigger the host provider service
734 verify(mockHostProviderService);
735 reset(mockHostProviderService);
Charles Chan64a1c8e2019-01-23 15:03:17 -0800736 assertAfter(PKT_PROCESSING_MS, () -> assertEquals(2, mockRouteStore.routes.size())); // ipAddress and prefix
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000737
Charles Chan64a1c8e2019-01-23 15:03:17 -0800738 assertAfter(PKT_PROCESSING_MS, () ->
739 assertTrue(mockRouteStore.routes.stream().anyMatch(rt -> rt.prefix().contains(IP_FOR_CLIENT_V6))));
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000740
Charles Chan64a1c8e2019-01-23 15:03:17 -0800741 assertAfter(PKT_PROCESSING_MS, () ->
742 assertTrue(mockRouteStore.routes.stream().anyMatch(rt -> rt.prefix().contains(PREFIX_FOR_CLIENT_V6))));
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000743
744 // send release msg
745 packetService.processPacket(new TestDhcp6RequestPacketContext(DHCP6.MsgType.RELEASE.value(),
746 CLIENT2_MAC,
747 CLIENT2_VLAN,
748 CLIENT2_CP,
749 OUTER_RELAY_IP_V6,
750 1));
Charles Chan64a1c8e2019-01-23 15:03:17 -0800751 assertAfter(PKT_PROCESSING_MS, () ->
752 assertFalse(mockRouteStore.routes.stream().anyMatch(rt -> rt.prefix().contains(IP_FOR_CLIENT_V6))));
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000753
Charles Chan64a1c8e2019-01-23 15:03:17 -0800754 assertAfter(PKT_PROCESSING_MS, () ->
755 assertFalse(mockRouteStore.routes.stream().anyMatch(rt -> rt.prefix().contains(PREFIX_FOR_CLIENT_V6))));
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000756
Charles Chan64a1c8e2019-01-23 15:03:17 -0800757 assertAfter(PKT_PROCESSING_MS, () -> assertEquals(0, mockRouteStore.routes.size()));
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000758
759 }
760
761 /**
762 * Relay a DHCP6 packet with Relay Message opion (Indirectly connected host) and server responded
763 * with vlan differnt from client interface vlan.
764 */
765 @Test
766 public void relayDhcp6WithAgentInfoWrongVlan() {
767 replay(mockHostProviderService);
768 // Assume outer dhcp6 relay agent exists in store already
769 // send request
770 packetService.processPacket(new TestDhcp6RequestPacketContext(DHCP6.MsgType.REQUEST.value(),
771 CLIENT2_MAC,
Kalhee Kim45fede42017-09-05 19:05:06 +0000772 CLIENT2_VLAN,
773 CLIENT2_CP,
774 INTERFACE_IP_V6.ipAddress().getIp6Address(),
775 1));
776
Charles Chan64a1c8e2019-01-23 15:03:17 -0800777 assertAfter(PKT_PROCESSING_MS, () -> assertEquals(0, mockRouteStore.routes.size()));
Kalhee Kim45fede42017-09-05 19:05:06 +0000778
779 // send reply
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000780 packetService.processPacket(new TestDhcp6ReplyPacketContext(DHCP6.MsgType.REPLY.value(),
781 CLIENT2_CP,
Kalhee Kim45fede42017-09-05 19:05:06 +0000782 CLIENT2_MAC,
Kalhee Kim121ba922017-11-01 17:56:44 +0000783 CLIENT2_VLAN,
Kalhee Kim45fede42017-09-05 19:05:06 +0000784 INTERFACE_IP_V6.ipAddress().getIp6Address(),
Kalhee Kim121ba922017-11-01 17:56:44 +0000785 1, true,
786 CLIENT_BOGUS_VLAN // mismatch
787 ));
Kalhee Kim45fede42017-09-05 19:05:06 +0000788
Yi Tsengaa417a62017-09-08 17:22:51 -0700789 // won't trigger the host provider service
790 verify(mockHostProviderService);
791 reset(mockHostProviderService);
Charles Chan64a1c8e2019-01-23 15:03:17 -0800792 assertAfter(PKT_PROCESSING_MS, () -> assertEquals(0, mockRouteStore.routes.size())); // ipAddress and prefix
Kalhee Kim45fede42017-09-05 19:05:06 +0000793
Kalhee Kim45fede42017-09-05 19:05:06 +0000794 }
Yi Tsengaa417a62017-09-08 17:22:51 -0700795
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000796
Yi Tsengaa417a62017-09-08 17:22:51 -0700797 @Test
798 public void testDhcp4DualHome() {
799 PacketContext packetContext =
800 new TestDhcpAckPacketContext(CLIENT_DH_CP, CLIENT_MAC, CLIENT_VLAN,
801 INTERFACE_IP.ipAddress().getIp4Address(),
802 false);
803 reset(manager.hostService);
804 expect(manager.hostService.getHost(CLIENT_HOST_ID)).andReturn(EXISTS_HOST).anyTimes();
805 Capture<HostDescription> capturedHostDesc = newCapture();
806 mockHostProviderService.hostDetected(eq(CLIENT_HOST_ID), capture(capturedHostDesc), eq(false));
807 replay(mockHostProviderService, manager.hostService);
808 packetService.processPacket(packetContext);
Charles Chan64a1c8e2019-01-23 15:03:17 -0800809 assertAfter(PKT_PROCESSING_MS, () -> verify(mockHostProviderService));
Yi Tsengaa417a62017-09-08 17:22:51 -0700810
Charles Chan64a1c8e2019-01-23 15:03:17 -0800811 assertAfter(PKT_PROCESSING_MS, () -> assertTrue(capturedHostDesc.hasCaptured()));
Yi Tsengaa417a62017-09-08 17:22:51 -0700812 HostDescription hostDesc = capturedHostDesc.getValue();
813 Set<HostLocation> hostLocations = hostDesc.locations();
Charles Chan64a1c8e2019-01-23 15:03:17 -0800814
815 assertAfter(PKT_PROCESSING_MS, () -> assertEquals(2, hostLocations.size()));
816 assertAfter(PKT_PROCESSING_MS, () -> assertTrue(hostLocations.contains(CLIENT_LOCATION)));
817 assertAfter(PKT_PROCESSING_MS, () -> assertTrue(hostLocations.contains(CLIENT_DH_LOCATION)));
Yi Tsengaa417a62017-09-08 17:22:51 -0700818 }
819
820 @Test
821 public void testDhcp6DualHome() {
822 PacketContext packetContext =
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000823 new TestDhcp6ReplyPacketContext(DHCP6.MsgType.REPLY.value(),
824 CLIENT_DH_CP, CLIENT_MAC, CLIENT_VLAN,
Yi Tsengaa417a62017-09-08 17:22:51 -0700825 INTERFACE_IP_V6.ipAddress().getIp6Address(),
Kalhee Kim121ba922017-11-01 17:56:44 +0000826 0, false, CLIENT_VLAN);
Yi Tsengaa417a62017-09-08 17:22:51 -0700827 reset(manager.hostService);
828 expect(manager.hostService.getHostsByIp(CLIENT_LL_IP_V6)).andReturn(ImmutableSet.of(EXISTS_HOST)).anyTimes();
829
830 // FIXME: currently DHCPv6 has a bug, we can't get correct vlan of client......
831 // XXX: The vlan relied from DHCP6 handler might be wrong, do hack here
832 HostId hostId = HostId.hostId(CLIENT_MAC, VlanId.NONE);
833 expect(manager.hostService.getHost(hostId)).andReturn(EXISTS_HOST).anyTimes();
834
835 // XXX: sometimes this will work, sometimes not
836 expect(manager.hostService.getHost(CLIENT_HOST_ID)).andReturn(EXISTS_HOST).anyTimes();
837
838 Capture<HostDescription> capturedHostDesc = newCapture();
839
840 // XXX: also a hack here
841 mockHostProviderService.hostDetected(eq(hostId), capture(capturedHostDesc), eq(false));
842 expectLastCall().anyTimes();
843
844 mockHostProviderService.hostDetected(eq(CLIENT_HOST_ID), capture(capturedHostDesc), eq(false));
845 expectLastCall().anyTimes();
846 replay(mockHostProviderService, manager.hostService);
847 packetService.processPacket(packetContext);
Charles Chan64a1c8e2019-01-23 15:03:17 -0800848 assertAfter(PKT_PROCESSING_MS, () -> verify(mockHostProviderService));
Yi Tsengaa417a62017-09-08 17:22:51 -0700849
Charles Chan64a1c8e2019-01-23 15:03:17 -0800850 assertAfter(PKT_PROCESSING_MS, () -> assertTrue(capturedHostDesc.hasCaptured()));
Yi Tsengaa417a62017-09-08 17:22:51 -0700851 HostDescription hostDesc = capturedHostDesc.getValue();
852 Set<HostLocation> hostLocations = hostDesc.locations();
Charles Chan64a1c8e2019-01-23 15:03:17 -0800853 assertAfter(PKT_PROCESSING_MS, () -> assertEquals(2, hostLocations.size()));
854 assertAfter(PKT_PROCESSING_MS, () -> assertTrue(hostLocations.contains(CLIENT_LOCATION)));
855 assertAfter(PKT_PROCESSING_MS, () -> assertTrue(hostLocations.contains(CLIENT_DH_LOCATION)));
Yi Tsengaa417a62017-09-08 17:22:51 -0700856 }
857
Yi Tseng483ac6f2017-08-02 15:03:31 -0700858 private static class MockDefaultDhcpRelayConfig extends DefaultDhcpRelayConfig {
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700859 @Override
860 public boolean isValid() {
861 return true;
862 }
863
864 @Override
Yi Tseng483ac6f2017-08-02 15:03:31 -0700865 public List<DhcpServerConfig> dhcpServerConfigs() {
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700866 return ImmutableList.of(new MockDhcpServerConfig(null));
Yi Tseng483ac6f2017-08-02 15:03:31 -0700867 }
868 }
869
Kalhee Kim45fede42017-09-05 19:05:06 +0000870 private static class MockIndirectDhcpRelayConfig extends IndirectDhcpRelayConfig {
871 @Override
872 public boolean isValid() {
873 return true;
874 }
875
876 @Override
877 public List<DhcpServerConfig> dhcpServerConfigs() {
878 return ImmutableList.of(new MockDhcpServerConfig(null));
879 }
880 }
881
Yi Tseng483ac6f2017-08-02 15:03:31 -0700882 private static class MockDhcpServerConfig extends DhcpServerConfig {
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700883 Ip4Address relayAgentIp;
884
885 /**
886 * Create mocked version DHCP server config.
887 *
888 * @param relayAgentIp the relay agent Ip config; null if we don't need it
889 */
890 public MockDhcpServerConfig(Ip4Address relayAgentIp) {
891 this.relayAgentIp = relayAgentIp;
Yi Tseng25bfe372017-11-03 16:27:32 -0700892 this.relayAgentIps.put(DEV_1_ID, Pair.of(relayAgentIp, null));
893 this.relayAgentIps.put(DEV_2_ID, Pair.of(relayAgentIp, null));
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700894 }
895
896 @Override
Yi Tseng25bfe372017-11-03 16:27:32 -0700897 public Optional<Ip4Address> getRelayAgentIp4(DeviceId deviceId) {
898 return Optional.ofNullable(this.relayAgentIps.get(deviceId).getLeft());
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700899 }
900
Yi Tseng483ac6f2017-08-02 15:03:31 -0700901 @Override
902 public Optional<ConnectPoint> getDhcpServerConnectPoint() {
903 return Optional.of(SERVER_CONNECT_POINT);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700904 }
905
Yi Tseng483ac6f2017-08-02 15:03:31 -0700906 @Override
907 public Optional<Ip4Address> getDhcpServerIp4() {
908 return Optional.of(SERVER_IP);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700909 }
Kalhee Kim45fede42017-09-05 19:05:06 +0000910
911 @Override
912 public Optional<Ip4Address> getDhcpGatewayIp4() {
913 return Optional.of(GATEWAY_IP);
914 }
915
916 @Override
917 public Optional<Ip6Address> getDhcpServerIp6() {
918 return Optional.of(SERVER_IP_V6);
919 }
920
921 @Override
922 public Optional<Ip6Address> getDhcpGatewayIp6() {
923 return Optional.of(GATEWAY_IP_V6);
924 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700925 }
926
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700927 private class MockRouteStore extends RouteStoreAdapter {
928 private List<Route> routes = Lists.newArrayList();
929
930 @Override
931 public void updateRoute(Route route) {
932 routes.add(route);
933 }
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000934
935 @Override
936 public void removeRoute(Route route) {
937 routes.remove(route);
938 }
Daniel Ginsburg83b76452018-06-09 01:43:59 +0300939
Charles Chan64a1c8e2019-01-23 15:03:17 -0800940 @Override
Daniel Ginsburg83b76452018-06-09 01:43:59 +0300941 public void replaceRoute(Route route) {
942 routes.remove(route);
943 routes.add(route);
944 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700945 }
946
947 private class MockInterfaceService extends InterfaceServiceAdapter {
948
949 @Override
950 public Set<Interface> getInterfaces() {
951 return INTERFACES;
952 }
953
954 @Override
955 public Set<Interface> getInterfacesByIp(IpAddress ip) {
956 return INTERFACES.stream()
957 .filter(iface -> {
958 return iface.ipAddressesList().stream()
959 .anyMatch(ifaceIp -> ifaceIp.ipAddress().equals(ip));
960 })
961 .collect(Collectors.toSet());
962 }
963
964 @Override
965 public Set<Interface> getInterfacesByPort(ConnectPoint port) {
966 return INTERFACES.stream()
967 .filter(iface -> iface.connectPoint().equals(port))
968 .collect(Collectors.toSet());
969 }
970 }
971
972 private class MockDhcpRelayStore implements DhcpRelayStore {
973 StoreDelegate<DhcpRelayStoreEvent> delegate;
974 private Map<HostId, DhcpRecord> records = Maps.newHashMap();
975
976 @Override
977 public void updateDhcpRecord(HostId hostId, DhcpRecord dhcpRecord) {
978 records.put(hostId, dhcpRecord);
979 DhcpRelayStoreEvent event = new DhcpRelayStoreEvent(DhcpRelayStoreEvent.Type.UPDATED,
980 dhcpRecord);
981 if (delegate != null) {
982 delegate.notify(event);
983 }
984 }
985
986 @Override
987 public Optional<DhcpRecord> getDhcpRecord(HostId hostId) {
988 return Optional.ofNullable(records.get(hostId));
989 }
990
991 @Override
992 public Collection<DhcpRecord> getDhcpRecords() {
993 return records.values();
994 }
995
996 @Override
997 public Optional<DhcpRecord> removeDhcpRecord(HostId hostId) {
998 DhcpRecord dhcpRecord = records.remove(hostId);
999 if (dhcpRecord != null) {
1000 DhcpRelayStoreEvent event = new DhcpRelayStoreEvent(DhcpRelayStoreEvent.Type.REMOVED,
1001 dhcpRecord);
1002 if (delegate != null) {
1003 delegate.notify(event);
1004 }
1005 }
1006 return Optional.ofNullable(dhcpRecord);
1007 }
1008
1009 @Override
1010 public void setDelegate(StoreDelegate<DhcpRelayStoreEvent> delegate) {
1011 this.delegate = delegate;
1012 }
1013
1014 @Override
1015 public void unsetDelegate(StoreDelegate<DhcpRelayStoreEvent> delegate) {
1016 this.delegate = null;
1017 }
1018
1019 @Override
1020 public boolean hasDelegate() {
1021 return this.delegate != null;
1022 }
1023 }
1024
Kalhee Kimd94ceea2017-11-29 19:03:02 +00001025 private class MockDhcpRelayCountersStore implements DhcpRelayCountersStore {
1026 private Map<String, DhcpRelayCounters> counters = Maps.newHashMap();
1027
1028 public void incrementCounter(String coutnerClass, String counterName) {
1029 DhcpRelayCounters countersRecord;
1030
1031 DhcpRelayCounters classCounters = counters.get(coutnerClass);
1032 if (classCounters == null) {
1033 classCounters = new DhcpRelayCounters();
1034 }
1035 classCounters.incrementCounter(counterName);
1036 counters.put(coutnerClass, classCounters);
1037 }
1038
1039 @Override
1040 public Set<Map.Entry<String, DhcpRelayCounters>> getAllCounters() {
1041 return counters.entrySet();
1042 }
1043
1044 @Override
1045 public Optional<DhcpRelayCounters> getCounters(String counterClass) {
1046 DhcpRelayCounters classCounters = counters.get(counterClass);
1047 if (classCounters == null) {
1048 return Optional.empty();
1049 }
1050 return Optional.of(classCounters);
1051 }
1052
1053 @Override
1054 public void resetAllCounters() {
1055 counters.clear();
1056 }
1057
1058 @Override
1059 public void resetCounters(String counterClass) {
1060 DhcpRelayCounters classCounters = counters.get(counterClass);
1061 classCounters.resetCounters();
1062 counters.put(counterClass, classCounters);
1063 }
1064 }
1065
1066
Yi Tseng7a38f9a2017-06-09 14:36:40 -07001067 private class MockPacketService extends PacketServiceAdapter {
1068 Set<PacketProcessor> packetProcessors = Sets.newHashSet();
Ray Milkeyc108a6b2017-08-23 15:23:50 -07001069 OutboundPacket emittedPacket;
Yi Tseng7a38f9a2017-06-09 14:36:40 -07001070
1071 @Override
1072 public void addProcessor(PacketProcessor processor, int priority) {
1073 packetProcessors.add(processor);
1074 }
1075
1076 public void processPacket(PacketContext packetContext) {
1077 packetProcessors.forEach(p -> p.process(packetContext));
1078 }
1079
1080 @Override
1081 public void emit(OutboundPacket packet) {
Ray Milkeyc108a6b2017-08-23 15:23:50 -07001082 this.emittedPacket = packet;
Yi Tseng7a38f9a2017-06-09 14:36:40 -07001083 }
1084 }
1085
1086
1087
1088 /**
1089 * Generates DHCP REQUEST packet.
1090 */
1091 private class TestDhcpRequestPacketContext extends PacketContextAdapter {
1092
1093
1094 private InboundPacket inPacket;
1095
1096 public TestDhcpRequestPacketContext(MacAddress clientMac, VlanId vlanId,
1097 ConnectPoint clientCp,
1098 Ip4Address clientGwAddr,
1099 boolean withNonOnosRelayInfo) {
1100 super(0, null, null, false);
1101 byte[] dhcpMsgType = new byte[1];
1102 dhcpMsgType[0] = (byte) DHCP.MsgType.DHCPREQUEST.getValue();
1103
1104 DhcpOption dhcpOption = new DhcpOption();
1105 dhcpOption.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue());
1106 dhcpOption.setData(dhcpMsgType);
1107 dhcpOption.setLength((byte) 1);
1108 DhcpOption endOption = new DhcpOption();
1109 endOption.setCode(DHCP.DHCPOptionCode.OptionCode_END.getValue());
1110
1111 DHCP dhcp = new DHCP();
1112 dhcp.setHardwareType(DHCP.HWTYPE_ETHERNET);
1113 dhcp.setHardwareAddressLength((byte) 6);
1114 dhcp.setClientHardwareAddress(clientMac.toBytes());
1115 if (withNonOnosRelayInfo) {
1116 DhcpRelayAgentOption relayOption = new DhcpRelayAgentOption();
1117 DhcpOption circuitIdOption = new DhcpOption();
1118 CircuitId circuitId = new CircuitId("Custom option", VlanId.NONE);
1119 byte[] cid = circuitId.serialize();
1120 circuitIdOption.setCode(DhcpRelayAgentOption.RelayAgentInfoOptions.CIRCUIT_ID.getValue());
1121 circuitIdOption.setLength((byte) cid.length);
1122 circuitIdOption.setData(cid);
1123 relayOption.setCode(DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue());
1124 relayOption.addSubOption(circuitIdOption);
1125 dhcp.setOptions(ImmutableList.of(dhcpOption, relayOption, endOption));
1126 dhcp.setGatewayIPAddress(OUTER_RELAY_IP.getIp4Address().toInt());
1127 } else {
1128 dhcp.setOptions(ImmutableList.of(dhcpOption, endOption));
1129 }
1130
1131
1132 UDP udp = new UDP();
1133 udp.setPayload(dhcp);
1134 udp.setSourcePort(UDP.DHCP_CLIENT_PORT);
1135 udp.setDestinationPort(UDP.DHCP_SERVER_PORT);
1136
1137 IPv4 ipv4 = new IPv4();
1138 ipv4.setPayload(udp);
1139 ipv4.setDestinationAddress(SERVER_IP.toInt());
1140 ipv4.setSourceAddress(clientGwAddr.toInt());
1141
1142 Ethernet eth = new Ethernet();
1143 if (withNonOnosRelayInfo) {
1144 eth.setEtherType(Ethernet.TYPE_IPV4)
1145 .setVlanID(vlanId.toShort())
1146 .setSourceMACAddress(OUTER_RELAY_MAC)
1147 .setDestinationMACAddress(MacAddress.BROADCAST)
1148 .setPayload(ipv4);
1149 } else {
1150 eth.setEtherType(Ethernet.TYPE_IPV4)
1151 .setVlanID(vlanId.toShort())
1152 .setSourceMACAddress(clientMac)
1153 .setDestinationMACAddress(MacAddress.BROADCAST)
1154 .setPayload(ipv4);
1155 }
1156
1157 this.inPacket = new DefaultInboundPacket(clientCp, eth,
1158 ByteBuffer.wrap(eth.serialize()));
1159 }
1160
1161 @Override
1162 public InboundPacket inPacket() {
1163 return this.inPacket;
1164 }
1165 }
1166
1167 /**
1168 * Generates DHCP ACK packet.
1169 */
1170 private class TestDhcpAckPacketContext extends PacketContextAdapter {
1171 private InboundPacket inPacket;
1172
1173 public TestDhcpAckPacketContext(ConnectPoint clientCp, MacAddress clientMac,
1174 VlanId clientVlan, Ip4Address clientGwAddr,
1175 boolean withNonOnosRelayInfo) {
1176 super(0, null, null, false);
1177
1178 byte[] dhcpMsgType = new byte[1];
1179 dhcpMsgType[0] = (byte) DHCP.MsgType.DHCPACK.getValue();
1180
1181 DhcpOption dhcpOption = new DhcpOption();
1182 dhcpOption.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue());
1183 dhcpOption.setData(dhcpMsgType);
1184 dhcpOption.setLength((byte) 1);
1185
1186 DhcpOption endOption = new DhcpOption();
1187 endOption.setCode(DHCP.DHCPOptionCode.OptionCode_END.getValue());
1188
1189 DHCP dhcp = new DHCP();
1190 if (withNonOnosRelayInfo) {
1191 DhcpRelayAgentOption relayOption = new DhcpRelayAgentOption();
1192 DhcpOption circuitIdOption = new DhcpOption();
Yi Tseng440e2b72017-08-24 14:47:34 -07001193 String circuitId = NON_ONOS_CID;
1194 byte[] cid = circuitId.getBytes(Charsets.US_ASCII);
Yi Tseng7a38f9a2017-06-09 14:36:40 -07001195 circuitIdOption.setCode(DhcpRelayAgentOption.RelayAgentInfoOptions.CIRCUIT_ID.getValue());
1196 circuitIdOption.setLength((byte) cid.length);
1197 circuitIdOption.setData(cid);
1198 relayOption.setCode(DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue());
1199 relayOption.addSubOption(circuitIdOption);
1200 dhcp.setOptions(ImmutableList.of(dhcpOption, relayOption, endOption));
1201 dhcp.setGatewayIPAddress(OUTER_RELAY_IP.getIp4Address().toInt());
1202 } else {
1203 CircuitId cid = new CircuitId(clientCp.toString(), clientVlan);
1204 byte[] circuitId = cid.serialize();
1205 DhcpOption circuitIdSubOption = new DhcpOption();
1206 circuitIdSubOption.setCode(DhcpRelayAgentOption.RelayAgentInfoOptions.CIRCUIT_ID.getValue());
1207 circuitIdSubOption.setData(circuitId);
1208 circuitIdSubOption.setLength((byte) circuitId.length);
1209
1210 DhcpRelayAgentOption relayInfoOption = new DhcpRelayAgentOption();
1211 relayInfoOption.setCode(DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue());
1212 relayInfoOption.addSubOption(circuitIdSubOption);
1213 dhcp.setOptions(ImmutableList.of(dhcpOption, relayInfoOption, endOption));
1214 dhcp.setGatewayIPAddress(clientGwAddr.toInt());
1215 }
1216 dhcp.setHardwareType(DHCP.HWTYPE_ETHERNET);
1217 dhcp.setHardwareAddressLength((byte) 6);
1218 dhcp.setClientHardwareAddress(clientMac.toBytes());
1219 dhcp.setYourIPAddress(IP_FOR_CLIENT.toInt());
1220
1221 UDP udp = new UDP();
1222 udp.setPayload(dhcp);
1223 udp.setSourcePort(UDP.DHCP_SERVER_PORT);
1224 udp.setDestinationPort(UDP.DHCP_CLIENT_PORT);
1225 IPv4 ipv4 = new IPv4();
1226 ipv4.setPayload(udp);
1227 ipv4.setDestinationAddress(IP_FOR_CLIENT.toString());
1228 ipv4.setSourceAddress(SERVER_IP.toString());
1229 Ethernet eth = new Ethernet();
1230 if (withNonOnosRelayInfo) {
1231 eth.setEtherType(Ethernet.TYPE_IPV4)
1232 .setVlanID(SERVER_VLAN.toShort())
1233 .setSourceMACAddress(SERVER_MAC)
1234 .setDestinationMACAddress(OUTER_RELAY_MAC)
1235 .setPayload(ipv4);
1236 } else {
1237 eth.setEtherType(Ethernet.TYPE_IPV4)
1238 .setVlanID(SERVER_VLAN.toShort())
1239 .setSourceMACAddress(SERVER_MAC)
1240 .setDestinationMACAddress(CLIENT_MAC)
1241 .setPayload(ipv4);
1242 }
1243
1244 this.inPacket = new DefaultInboundPacket(SERVER_CONNECT_POINT, eth,
1245 ByteBuffer.wrap(eth.serialize()));
1246
1247 }
1248
1249 @Override
1250 public InboundPacket inPacket() {
1251 return this.inPacket;
1252 }
1253 }
1254
1255 private class TestArpRequestPacketContext extends PacketContextAdapter {
1256 private InboundPacket inPacket;
1257
1258 public TestArpRequestPacketContext(Interface fromInterface) {
1259 super(0, null, null, false);
1260 ARP arp = new ARP();
1261 arp.setOpCode(ARP.OP_REQUEST);
1262
1263 IpAddress targetIp = fromInterface.ipAddressesList().get(0).ipAddress();
1264 arp.setTargetProtocolAddress(targetIp.toOctets());
1265 arp.setTargetHardwareAddress(MacAddress.BROADCAST.toBytes());
1266 arp.setSenderHardwareAddress(MacAddress.NONE.toBytes());
1267 arp.setSenderProtocolAddress(Ip4Address.valueOf(0).toOctets());
1268 arp.setHardwareAddressLength((byte) MacAddress.MAC_ADDRESS_LENGTH);
1269 Ethernet eth = new Ethernet();
1270 eth.setEtherType(Ethernet.TYPE_ARP);
1271 eth.setSourceMACAddress(MacAddress.NONE);
1272 eth.setDestinationMACAddress(MacAddress.BROADCAST);
1273 eth.setVlanID(fromInterface.vlan().toShort());
1274 eth.setPayload(arp);
1275
1276 this.inPacket = new DefaultInboundPacket(fromInterface.connectPoint(), eth,
1277 ByteBuffer.wrap(eth.serialize()));
1278 }
1279
1280 @Override
1281 public InboundPacket inPacket() {
1282 return this.inPacket;
1283 }
1284 }
Kalhee Kim45fede42017-09-05 19:05:06 +00001285
1286 /**
1287 * Generates DHCP6 REQUEST packet.
1288 */
1289 private void buildDhcp6Packet(DHCP6 dhcp6, byte msgType, Ip6Address ip6Addr, IpPrefix prefix) {
1290
1291 // build address option
1292 Dhcp6IaAddressOption iaAddressOption = new Dhcp6IaAddressOption();
1293 iaAddressOption.setCode(DHCP6.OptionCode.IAADDR.value());
1294 iaAddressOption.setIp6Address(ip6Addr);
1295 iaAddressOption.setPreferredLifetime(3600);
1296 iaAddressOption.setValidLifetime(1200);
1297 iaAddressOption.setLength((short) Dhcp6IaAddressOption.DEFAULT_LEN);
1298
Kalhee Kim495c9b22017-11-07 16:32:09 +00001299 Dhcp6ClientIdOption clientIdOption = new Dhcp6ClientIdOption();
1300 Dhcp6Duid dhcp6Duip = new Dhcp6Duid();
1301 dhcp6Duip.setDuidType(Dhcp6Duid.DuidType.DUID_LLT);
1302 dhcp6Duip.setHardwareType((short) 0x01); // Ethernet
1303 dhcp6Duip.setDuidTime(1234);
1304 dhcp6Duip.setLinkLayerAddress(CLIENT_MAC.toBytes());
1305 clientIdOption.setDuid(dhcp6Duip);
1306
Kalhee Kim45fede42017-09-05 19:05:06 +00001307 Dhcp6IaNaOption iaNaOption = new Dhcp6IaNaOption();
1308 iaNaOption.setCode(DHCP6.OptionCode.IA_NA.value());
1309 iaNaOption.setIaId(0);
1310 iaNaOption.setT1(302400);
1311 iaNaOption.setT2(483840);
1312 List<Dhcp6Option> iaNaSubOptions = new ArrayList<Dhcp6Option>();
1313 iaNaSubOptions.add(iaAddressOption);
1314 iaNaOption.setOptions(iaNaSubOptions);
1315 iaNaOption.setLength((short) (Dhcp6IaNaOption.DEFAULT_LEN + iaAddressOption.getLength()));
1316
1317 // build prefix option
1318 Dhcp6IaPrefixOption iaPrefixOption = new Dhcp6IaPrefixOption();
1319 iaPrefixOption.setCode(DHCP6.OptionCode.IAPREFIX.value());
1320 iaPrefixOption.setIp6Prefix(prefix.address().getIp6Address());
1321 iaPrefixOption.setPrefixLength((byte) prefix.prefixLength());
1322 iaPrefixOption.setPreferredLifetime(3601);
1323 iaPrefixOption.setValidLifetime(1201);
1324 iaPrefixOption.setLength((short) Dhcp6IaPrefixOption.DEFAULT_LEN);
1325
1326 Dhcp6IaPdOption iaPdOption = new Dhcp6IaPdOption();
1327 iaPdOption.setCode(DHCP6.OptionCode.IA_PD.value());
1328 iaPdOption.setIaId(0);
1329 iaPdOption.setT1(302401);
1330 iaPdOption.setT2(483841);
1331 List<Dhcp6Option> iaPdSubOptions = new ArrayList<Dhcp6Option>();
1332 iaPdSubOptions.add(iaPrefixOption);
1333 iaPdOption.setOptions(iaPdSubOptions);
1334 iaPdOption.setLength((short) (Dhcp6IaPdOption.DEFAULT_LEN + iaPrefixOption.getLength()));
1335
1336 dhcp6.setMsgType(msgType);
1337 List<Dhcp6Option> dhcp6Options = new ArrayList<Dhcp6Option>();
1338 dhcp6Options.add(iaNaOption);
Kalhee Kim495c9b22017-11-07 16:32:09 +00001339 dhcp6Options.add(clientIdOption);
Kalhee Kim45fede42017-09-05 19:05:06 +00001340 dhcp6Options.add(iaPdOption);
1341 dhcp6.setOptions(dhcp6Options);
1342
1343 }
1344
1345 private void buildRelayMsg(DHCP6 dhcp6Relay, byte msgType, Ip6Address linkAddr,
1346 Ip6Address peerAddr, byte hop, byte[] interfaceIdBytes,
1347 DHCP6 dhcp6Payload) {
1348
1349 dhcp6Relay.setMsgType(msgType);
1350
1351 dhcp6Relay.setLinkAddress(linkAddr.toOctets());
1352 dhcp6Relay.setPeerAddress(peerAddr.toOctets());
1353 dhcp6Relay.setHopCount(hop);
1354 List<Dhcp6Option> options = new ArrayList<Dhcp6Option>();
1355
1356 // interfaceId option
1357 Dhcp6Option interfaceId = new Dhcp6Option();
1358 interfaceId.setCode(DHCP6.OptionCode.INTERFACE_ID.value());
1359
1360
1361 interfaceId.setData(interfaceIdBytes);
1362 interfaceId.setLength((short) interfaceIdBytes.length);
1363 Dhcp6InterfaceIdOption interfaceIdOption = new Dhcp6InterfaceIdOption(interfaceId);
Kalhee Kima0b8f652017-10-18 22:00:30 +00001364 byte[] optionData = interfaceIdOption.getData();
Kalhee Kim45fede42017-09-05 19:05:06 +00001365 ByteBuffer bb = ByteBuffer.wrap(interfaceIdBytes);
1366
1367 byte[] macAddr = new byte[MacAddress.MAC_ADDRESS_LENGTH];
Kalhee Kima0b8f652017-10-18 22:00:30 +00001368 byte[] port = new byte[optionData.length - MacAddress.MAC_ADDRESS_LENGTH -
Kalhee Kimba366062017-11-07 16:32:09 +00001369 VLAN_LEN - SEPARATOR_LEN * 2];
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001370 short vlan;
Kalhee Kim45fede42017-09-05 19:05:06 +00001371 bb.get(macAddr);
1372 bb.get(); // separator
1373 bb.get(port);
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001374 bb.get(); // separator
1375 vlan = bb.getShort();
Kalhee Kim45fede42017-09-05 19:05:06 +00001376 interfaceIdOption.setMacAddress(MacAddress.valueOf(macAddr));
1377 interfaceIdOption.setInPort(port);
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001378 interfaceIdOption.setVlanId(vlan);
Kalhee Kim45fede42017-09-05 19:05:06 +00001379
1380 options.add(interfaceIdOption);
1381
1382 // relay message option
1383 Dhcp6Option relayMsgOption = new Dhcp6Option();
1384 relayMsgOption.setCode(DHCP6.OptionCode.RELAY_MSG.value());
1385 byte[] dhcp6PayloadByte = dhcp6Payload.serialize();
1386 relayMsgOption.setLength((short) dhcp6PayloadByte.length);
1387 relayMsgOption.setPayload(dhcp6Payload);
1388 Dhcp6RelayOption relayOpt = new Dhcp6RelayOption(relayMsgOption);
1389
1390 options.add(relayOpt);
1391
1392 dhcp6Relay.setOptions(options);
1393 }
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001394 private byte[] buildInterfaceId(MacAddress clientMac, short vlanId, ConnectPoint clientCp) {
1395 String inPortString = "-" + clientCp.toString() + ":";
Kalhee Kim45fede42017-09-05 19:05:06 +00001396 byte[] clientSoureMacBytes = clientMac.toBytes();
1397 byte[] inPortStringBytes = inPortString.getBytes();
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001398 byte[] vlanIdBytes = new byte[2];
1399 vlanIdBytes[0] = (byte) ((vlanId >> 8) & 0xff); // high-order byte first
1400 vlanIdBytes[1] = (byte) (vlanId & 0xff);
1401 byte[] interfaceIdBytes = new byte[clientSoureMacBytes.length + inPortStringBytes.length + vlanIdBytes.length];
Kalhee Kim45fede42017-09-05 19:05:06 +00001402
1403 System.arraycopy(clientSoureMacBytes, 0, interfaceIdBytes, 0, clientSoureMacBytes.length);
1404 System.arraycopy(inPortStringBytes, 0, interfaceIdBytes, clientSoureMacBytes.length, inPortStringBytes.length);
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001405 System.arraycopy(vlanIdBytes, 0, interfaceIdBytes, clientSoureMacBytes.length + inPortStringBytes.length,
1406 vlanIdBytes.length);
Kalhee Kim45fede42017-09-05 19:05:06 +00001407
1408 return interfaceIdBytes;
1409 }
1410
Yi Tseng525ff402017-10-23 19:39:39 -07001411 private static List<TrafficSelector> buildClientDhcpSelectors() {
1412 return Streams.concat(Dhcp4HandlerImpl.DHCP_SELECTORS.stream(),
1413 Dhcp6HandlerImpl.DHCP_SELECTORS.stream())
1414 .collect(Collectors.toList());
1415 }
1416
Kalhee Kim45fede42017-09-05 19:05:06 +00001417 private class TestDhcp6RequestPacketContext extends PacketContextAdapter {
1418
1419
1420 private InboundPacket inPacket;
1421
1422
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001423 public TestDhcp6RequestPacketContext(byte msgType, MacAddress clientMac, VlanId vlanId,
Kalhee Kim45fede42017-09-05 19:05:06 +00001424 ConnectPoint clientCp,
1425 Ip6Address clientGwAddr,
1426 int relayLevel) {
1427 super(0, null, null, false);
1428
1429 DHCP6 dhcp6 = new DHCP6();
1430 if (relayLevel > 0) {
1431 DHCP6 dhcp6Payload = new DHCP6();
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001432 buildDhcp6Packet(dhcp6Payload, msgType,
Kalhee Kim45fede42017-09-05 19:05:06 +00001433 IP_FOR_CLIENT_V6,
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001434 msgType == DHCP6.MsgType.REQUEST.value() ? PREFIX_FOR_ZERO : PREFIX_FOR_CLIENT_V6);
Kalhee Kim45fede42017-09-05 19:05:06 +00001435 DHCP6 dhcp6Parent = null;
1436 DHCP6 dhcp6Child = dhcp6Payload;
1437 for (int i = 0; i < relayLevel; i++) {
1438 dhcp6Parent = new DHCP6();
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001439 byte[] interfaceId = buildInterfaceId(clientMac, vlanId.toShort(), clientCp);
Kalhee Kim45fede42017-09-05 19:05:06 +00001440 buildRelayMsg(dhcp6Parent, DHCP6.MsgType.RELAY_FORW.value(),
1441 INTERFACE_IP_V6.ipAddress().getIp6Address(),
1442 OUTER_RELAY_IP_V6,
1443 (byte) (relayLevel - 1), interfaceId,
1444 dhcp6Child);
1445 dhcp6Child = dhcp6Parent;
1446 }
1447 if (dhcp6Parent != null) {
1448 dhcp6 = dhcp6Parent;
1449 }
1450 } else {
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001451 buildDhcp6Packet(dhcp6, msgType,
Kalhee Kim45fede42017-09-05 19:05:06 +00001452 IP_FOR_CLIENT_V6,
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001453 msgType == DHCP6.MsgType.REQUEST.value() ? PREFIX_FOR_ZERO : PREFIX_FOR_CLIENT_V6);
Kalhee Kim45fede42017-09-05 19:05:06 +00001454 }
1455
1456 UDP udp = new UDP();
1457 udp.setPayload(dhcp6);
1458 if (relayLevel > 0) {
1459 udp.setSourcePort(UDP.DHCP_V6_SERVER_PORT);
1460 } else {
1461 udp.setSourcePort(UDP.DHCP_V6_CLIENT_PORT);
1462 }
1463 udp.setDestinationPort(UDP.DHCP_V6_SERVER_PORT);
1464
1465 IPv6 ipv6 = new IPv6();
1466 ipv6.setPayload(udp);
1467 ipv6.setNextHeader(IPv6.PROTOCOL_UDP);
1468 ipv6.setDestinationAddress(SERVER_IP_V6_MCAST.toOctets());
1469 ipv6.setSourceAddress(clientGwAddr.toOctets());
1470
1471 Ethernet eth = new Ethernet();
1472 if (relayLevel > 0) {
1473 eth.setEtherType(Ethernet.TYPE_IPV6)
Kalhee Kim121ba922017-11-01 17:56:44 +00001474 .setVlanID(OUTER_RELAY_VLAN.toShort())
Kalhee Kim45fede42017-09-05 19:05:06 +00001475 .setSourceMACAddress(OUTER_RELAY_MAC)
1476 .setDestinationMACAddress(MacAddress.valueOf("33:33:00:01:00:02"))
1477 .setPayload(ipv6);
1478 } else {
1479 eth.setEtherType(Ethernet.TYPE_IPV6)
1480 .setVlanID(vlanId.toShort())
1481 .setSourceMACAddress(clientMac)
1482 .setDestinationMACAddress(MacAddress.valueOf("33:33:00:01:00:02"))
1483 .setPayload(ipv6);
1484 }
1485 this.inPacket = new DefaultInboundPacket(clientCp, eth,
1486 ByteBuffer.wrap(eth.serialize()));
1487 }
1488
1489 @Override
1490 public InboundPacket inPacket() {
1491 return this.inPacket;
1492 }
1493 }
1494
1495 /**
1496 * Generates DHCP6 REPLY packet.
1497 */
1498
1499 private class TestDhcp6ReplyPacketContext extends PacketContextAdapter {
1500 private InboundPacket inPacket;
1501
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001502 public TestDhcp6ReplyPacketContext(byte msgType, ConnectPoint clientCp, MacAddress clientMac,
Kalhee Kim45fede42017-09-05 19:05:06 +00001503 VlanId clientVlan, Ip6Address clientGwAddr,
Kalhee Kim121ba922017-11-01 17:56:44 +00001504 int relayLevel, boolean overWriteFlag, VlanId overWriteVlan) {
Kalhee Kim45fede42017-09-05 19:05:06 +00001505 super(0, null, null, false);
1506
1507
1508 DHCP6 dhcp6Payload = new DHCP6();
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001509 buildDhcp6Packet(dhcp6Payload, msgType,
Kalhee Kim45fede42017-09-05 19:05:06 +00001510 IP_FOR_CLIENT_V6,
1511 PREFIX_FOR_CLIENT_V6);
Kalhee Kim121ba922017-11-01 17:56:44 +00001512 byte[] interfaceId = null;
1513 if (relayLevel > 0) {
1514 interfaceId = buildInterfaceId(OUTER_RELAY_MAC,
1515 overWriteFlag ? overWriteVlan.toShort() : OUTER_RELAY_VLAN.toShort(),
1516 OUTER_RELAY_CP);
1517 } else {
1518 interfaceId = buildInterfaceId(clientMac, clientVlan.toShort(), clientCp);
1519 }
Kalhee Kim45fede42017-09-05 19:05:06 +00001520 DHCP6 dhcp6 = new DHCP6();
1521 buildRelayMsg(dhcp6, DHCP6.MsgType.RELAY_REPL.value(),
Yi Tsengaa417a62017-09-08 17:22:51 -07001522 INTERFACE_IP_V6.ipAddress().getIp6Address(),
1523 CLIENT_LL_IP_V6,
1524 (byte) 0, interfaceId,
1525 dhcp6Payload);
Kalhee Kim45fede42017-09-05 19:05:06 +00001526
1527 DHCP6 dhcp6Parent = null;
1528 DHCP6 dhcp6Child = dhcp6;
1529 for (int i = 0; i < relayLevel; i++) { // relayLevel 0 : no relay
1530 dhcp6Parent = new DHCP6();
1531
1532 buildRelayMsg(dhcp6Parent, DHCP6.MsgType.RELAY_REPL.value(),
1533 INTERFACE_IP_V6.ipAddress().getIp6Address(),
1534 OUTER_RELAY_IP_V6,
1535 (byte) relayLevel, interfaceId,
1536 dhcp6Child);
1537
1538 dhcp6Child = dhcp6Parent;
1539 }
1540 if (dhcp6Parent != null) {
1541 dhcp6 = dhcp6Parent;
1542 }
1543
1544
1545 UDP udp = new UDP();
1546 udp.setPayload(dhcp6);
1547 udp.setSourcePort(UDP.DHCP_V6_SERVER_PORT);
1548 udp.setDestinationPort(UDP.DHCP_V6_CLIENT_PORT);
1549 IPv6 ipv6 = new IPv6();
1550 ipv6.setPayload(udp);
1551 ipv6.setNextHeader(IPv6.PROTOCOL_UDP);
1552 ipv6.setDestinationAddress(IP_FOR_CLIENT_V6.toOctets());
1553 ipv6.setSourceAddress(SERVER_IP_V6.toOctets());
1554 Ethernet eth = new Ethernet();
1555 if (relayLevel > 0) {
1556 eth.setEtherType(Ethernet.TYPE_IPV6)
1557 .setVlanID(SERVER_VLAN.toShort())
1558 .setSourceMACAddress(SERVER_MAC)
1559 .setDestinationMACAddress(OUTER_RELAY_MAC)
1560 .setPayload(ipv6);
1561 } else {
1562 eth.setEtherType(Ethernet.TYPE_IPV6)
1563 .setVlanID(SERVER_VLAN.toShort())
1564 .setSourceMACAddress(SERVER_MAC)
1565 .setDestinationMACAddress(CLIENT_MAC)
1566 .setPayload(ipv6);
1567 }
1568
1569 this.inPacket = new DefaultInboundPacket(SERVER_CONNECT_POINT, eth,
1570 ByteBuffer.wrap(eth.serialize()));
1571
1572 }
1573
1574 @Override
1575 public InboundPacket inPacket() {
1576 return this.inPacket;
1577 }
1578 }
1579
Yi Tseng7a38f9a2017-06-09 14:36:40 -07001580}