blob: eb24ae2411ab5e3dbc9971b57e50b01496ac8117 [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 Tseng51f1be92017-09-01 17:24:57 -070028import org.easymock.Capture;
29import org.easymock.CaptureType;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070030import org.easymock.EasyMock;
31import org.junit.After;
32import org.junit.Before;
33import org.junit.Test;
34import org.onlab.packet.ARP;
35import org.onlab.packet.DHCP;
Yi Tseng3df7f9d2017-08-17 13:08:31 -070036import org.onlab.packet.DeserializationException;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070037import org.onlab.packet.Ethernet;
38import org.onlab.packet.IPv4;
39import org.onlab.packet.Ip4Address;
Kalhee Kim45fede42017-09-05 19:05:06 +000040import org.onlab.packet.Ip6Address;
41import org.onlab.packet.IpPrefix;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070042import org.onlab.packet.IpAddress;
43import org.onlab.packet.MacAddress;
44import org.onlab.packet.UDP;
45import org.onlab.packet.VlanId;
46import org.onlab.packet.dhcp.CircuitId;
47import org.onlab.packet.dhcp.DhcpOption;
48import org.onlab.packet.dhcp.DhcpRelayAgentOption;
Kalhee Kim45fede42017-09-05 19:05:06 +000049import org.onlab.packet.dhcp.Dhcp6InterfaceIdOption;
50import org.onlab.packet.dhcp.Dhcp6RelayOption;
51import org.onlab.packet.dhcp.Dhcp6IaNaOption;
52import org.onlab.packet.dhcp.Dhcp6IaPdOption;
53import org.onlab.packet.dhcp.Dhcp6IaAddressOption;
54import org.onlab.packet.dhcp.Dhcp6IaPrefixOption;
55import org.onlab.packet.dhcp.Dhcp6Option;
56import org.onosproject.net.ConnectPoint;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070057import org.onosproject.TestApplicationId;
58import org.onosproject.cfg.ComponentConfigService;
59import org.onosproject.core.ApplicationId;
60import org.onosproject.core.CoreService;
Yi Tseng483ac6f2017-08-02 15:03:31 -070061import org.onosproject.dhcprelay.config.DefaultDhcpRelayConfig;
62import org.onosproject.dhcprelay.config.DhcpServerConfig;
Yi Tseng51f1be92017-09-01 17:24:57 -070063import org.onosproject.dhcprelay.config.IgnoreDhcpConfig;
Yi Tseng483ac6f2017-08-02 15:03:31 -070064import org.onosproject.dhcprelay.config.IndirectDhcpRelayConfig;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070065import org.onosproject.dhcprelay.store.DhcpRecord;
66import org.onosproject.dhcprelay.store.DhcpRelayStore;
67import org.onosproject.dhcprelay.store.DhcpRelayStoreEvent;
Yi Tseng127ffe52017-09-12 15:55:17 -070068import org.onosproject.net.Device;
Yi Tseng51f1be92017-09-01 17:24:57 -070069import org.onosproject.net.DeviceId;
Yi Tseng127ffe52017-09-12 15:55:17 -070070import org.onosproject.net.behaviour.Pipeliner;
71import org.onosproject.net.device.DeviceEvent;
72import org.onosproject.net.device.DeviceService;
Yi Tseng51f1be92017-09-01 17:24:57 -070073import org.onosproject.net.flow.DefaultTrafficSelector;
74import org.onosproject.net.flow.DefaultTrafficTreatment;
75import org.onosproject.net.flow.TrafficSelector;
76import org.onosproject.net.flow.TrafficTreatment;
77import org.onosproject.net.flowobjective.FlowObjectiveService;
78import org.onosproject.net.flowobjective.ForwardingObjective;
79import org.onosproject.net.flowobjective.Objective;
Yi Tsengaa417a62017-09-08 17:22:51 -070080import org.onosproject.net.host.HostProviderService;
Ray Milkeyfacf2862017-08-03 11:58:29 -070081import org.onosproject.net.intf.Interface;
82import org.onosproject.net.intf.InterfaceServiceAdapter;
Yi Tseng51f1be92017-09-01 17:24:57 -070083import org.onosproject.net.packet.PacketPriority;
Ray Milkey69ec8712017-08-08 13:00:43 -070084import org.onosproject.routeservice.Route;
85import org.onosproject.routeservice.RouteStoreAdapter;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070086import org.onosproject.net.DefaultHost;
87import org.onosproject.net.Host;
88import org.onosproject.net.HostId;
89import org.onosproject.net.HostLocation;
90import org.onosproject.net.config.NetworkConfigRegistry;
91import org.onosproject.net.host.HostDescription;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070092import org.onosproject.net.host.HostService;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070093import org.onosproject.net.host.InterfaceIpAddress;
94import org.onosproject.net.packet.DefaultInboundPacket;
95import org.onosproject.net.packet.InboundPacket;
96import org.onosproject.net.packet.OutboundPacket;
97import org.onosproject.net.packet.PacketContext;
98import org.onosproject.net.packet.PacketContextAdapter;
99import org.onosproject.net.packet.PacketProcessor;
100import org.onosproject.net.packet.PacketServiceAdapter;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700101import org.onosproject.store.StoreDelegate;
102import org.osgi.service.component.ComponentContext;
Kalhee Kim45fede42017-09-05 19:05:06 +0000103import org.onlab.packet.DHCP6;
104import org.onlab.packet.IPv6;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700105
Yi Tseng127ffe52017-09-12 15:55:17 -0700106import java.io.IOException;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700107import java.nio.ByteBuffer;
108import java.util.Collection;
109import java.util.Dictionary;
110import java.util.List;
Kalhee Kim45fede42017-09-05 19:05:06 +0000111import java.util.ArrayList;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700112import java.util.Map;
113import java.util.Optional;
114import java.util.Set;
115import java.util.stream.Collectors;
116
117import static org.easymock.EasyMock.*;
118import static org.junit.Assert.*;
Yi Tseng51f1be92017-09-01 17:24:57 -0700119import static org.onosproject.dhcprelay.DhcpRelayManager.DHCP_RELAY_APP;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700120
121public class DhcpRelayManagerTest {
Kalhee Kima0b8f652017-10-18 22:00:30 +0000122 private static final short VLAN_LEN = 2;
123 private static final short SEPARATOR_LEN = 1;
Yi Tseng51f1be92017-09-01 17:24:57 -0700124 private static final String CONFIG_FILE_PATH = "dhcp-relay.json";
125 private static final DeviceId DEV_1_ID = DeviceId.deviceId("of:0000000000000001");
126 private static final DeviceId DEV_2_ID = DeviceId.deviceId("of:0000000000000002");
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700127 // Ip address for interfaces
128 private static final InterfaceIpAddress INTERFACE_IP = InterfaceIpAddress.valueOf("10.0.3.254/32");
Kalhee Kim45fede42017-09-05 19:05:06 +0000129 private static final InterfaceIpAddress INTERFACE_IP_V6 = InterfaceIpAddress.valueOf("2001:db8:1::254/128");
130 private static final List<InterfaceIpAddress> INTERFACE_IPS = ImmutableList.of(INTERFACE_IP, INTERFACE_IP_V6);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700131
132 // DHCP client (will send without option 82)
133 private static final Ip4Address IP_FOR_CLIENT = Ip4Address.valueOf("10.0.0.1");
Kalhee Kim45fede42017-09-05 19:05:06 +0000134 private static final Ip6Address IP_FOR_CLIENT_V6 = Ip6Address.valueOf("2001:db8:1::110");
135 private static final IpPrefix PREFIX_FOR_CLIENT_V6 = IpPrefix.valueOf("2001:db8:10::/56");
136 private static final IpPrefix PREFIX_FOR_ZERO = IpPrefix.valueOf("::/0");
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700137 private static final MacAddress CLIENT_MAC = MacAddress.valueOf("00:00:00:00:00:01");
138 private static final VlanId CLIENT_VLAN = VlanId.vlanId("100");
139 private static final ConnectPoint CLIENT_CP = ConnectPoint.deviceConnectPoint("of:0000000000000001/1");
140 private static final MacAddress CLIENT_IFACE_MAC = MacAddress.valueOf("00:00:00:00:11:01");
Yi Tsengaa417a62017-09-08 17:22:51 -0700141 private static final HostLocation CLIENT_LOCATION = new HostLocation(CLIENT_CP, 0);
142 private static final HostId CLIENT_HOST_ID = HostId.hostId(CLIENT_MAC, CLIENT_VLAN);
143 private static final Ip6Address CLIENT_LL_IP_V6 = Ip6Address.valueOf("fe80::200:00ff:fe00:0001");
Charles Chand988c282017-09-12 17:09:32 -0700144 private static final Host EXISTS_HOST = new DefaultHost(Dhcp4HandlerImpl.PROVIDER_ID,
Yi Tsengaa417a62017-09-08 17:22:51 -0700145 CLIENT_HOST_ID, CLIENT_MAC, CLIENT_VLAN,
146 CLIENT_LOCATION, ImmutableSet.of(CLIENT_LL_IP_V6));
Yi Tseng4025a102017-09-30 11:35:42 +0800147 private static final Interface CLIENT_INTERFACE = createInterface("C1",
148 CLIENT_CP,
149 INTERFACE_IPS,
150 CLIENT_IFACE_MAC,
151 CLIENT_VLAN,
152 null);
153
154
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700155
Yi Tsengaa417a62017-09-08 17:22:51 -0700156 // Dual homing test
157 private static final ConnectPoint CLIENT_DH_CP = ConnectPoint.deviceConnectPoint("of:0000000000000001/3");
158 private static final HostLocation CLIENT_DH_LOCATION = new HostLocation(CLIENT_DH_CP, 0);
Yi Tseng4025a102017-09-30 11:35:42 +0800159 private static final Interface CLIENT_DH_INTERFACE = createInterface("C1-DH",
160 CLIENT_DH_CP,
161 INTERFACE_IPS,
162 CLIENT_IFACE_MAC,
163 CLIENT_VLAN,
164 null);
Yi Tsengaa417a62017-09-08 17:22:51 -0700165
166
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700167 // DHCP client 2 (will send with option 82, so the vlan should equals to vlan from server)
168 private static final MacAddress CLIENT2_MAC = MacAddress.valueOf("00:00:00:00:00:01");
169 private static final VlanId CLIENT2_VLAN = VlanId.NONE;
Yi Tseng4025a102017-09-30 11:35:42 +0800170 private static final VlanId CLIENT2_VLAN_NATIVE = VlanId.vlanId("20");
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700171 private static final ConnectPoint CLIENT2_CP = ConnectPoint.deviceConnectPoint("of:0000000000000001/2");
172 private static final MacAddress CLIENT2_IFACE_MAC = MacAddress.valueOf("00:00:00:00:11:01");
Yi Tseng4025a102017-09-30 11:35:42 +0800173 private static final Interface CLIENT2_INTERFACE = createInterface("C2",
174 CLIENT2_CP,
175 INTERFACE_IPS,
176 CLIENT2_IFACE_MAC,
177 CLIENT2_VLAN,
178 CLIENT2_VLAN_NATIVE);
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000179 private static final VlanId CLIENT_BOGUS_VLAN = VlanId.vlanId("108");
180
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700181
182 // Outer relay information
183 private static final Ip4Address OUTER_RELAY_IP = Ip4Address.valueOf("10.0.5.253");
Kalhee Kim45fede42017-09-05 19:05:06 +0000184 private static final Ip6Address OUTER_RELAY_IP_V6 = Ip6Address.valueOf("2001:db8:1::4");
185 private static final Set<IpAddress> OUTER_RELAY_IPS = ImmutableSet.of(OUTER_RELAY_IP, OUTER_RELAY_IP_V6);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700186 private static final MacAddress OUTER_RELAY_MAC = MacAddress.valueOf("00:01:02:03:04:05");
187 private static final VlanId OUTER_RELAY_VLAN = VlanId.NONE;
188 private static final ConnectPoint OUTER_RELAY_CP = ConnectPoint.deviceConnectPoint("of:0000000000000001/2");
189 private static final HostLocation OUTER_REPLAY_HL = new HostLocation(OUTER_RELAY_CP, 0);
190 private static final HostId OUTER_RELAY_HOST_ID = HostId.hostId(OUTER_RELAY_MAC, OUTER_RELAY_VLAN);
Charles Chand988c282017-09-12 17:09:32 -0700191 private static final Host OUTER_RELAY_HOST = new DefaultHost(Dhcp4HandlerImpl.PROVIDER_ID,
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700192 OUTER_RELAY_HOST_ID,
193 OUTER_RELAY_MAC,
194 OUTER_RELAY_VLAN,
195 OUTER_REPLAY_HL,
196 OUTER_RELAY_IPS);
197
198 // DHCP Server
199 private static final MacAddress SERVER_MAC = MacAddress.valueOf("00:00:00:00:00:01");
200 private static final VlanId SERVER_VLAN = VlanId.NONE;
Yi Tseng4025a102017-09-30 11:35:42 +0800201 private static final VlanId SERVER_VLAN_NATIVE = VlanId.vlanId("10");
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700202 private static final ConnectPoint SERVER_CONNECT_POINT =
203 ConnectPoint.deviceConnectPoint("of:0000000000000001/5");
204 private static final HostLocation SERVER_LOCATION =
205 new HostLocation(SERVER_CONNECT_POINT, 0);
Kalhee Kim45fede42017-09-05 19:05:06 +0000206 private static final Ip4Address GATEWAY_IP = Ip4Address.valueOf("10.0.5.253");
207 private static final Ip6Address GATEWAY_IP_V6 = Ip6Address.valueOf("2000::105:253");
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700208 private static final Ip4Address SERVER_IP = Ip4Address.valueOf("10.0.3.253");
Kalhee Kim45fede42017-09-05 19:05:06 +0000209 private static final Ip6Address SERVER_IP_V6 = Ip6Address.valueOf("2000::103:253");
210 private static final Ip6Address SERVER_IP_V6_MCAST = Ip6Address.valueOf("ff02::1:2");
211 private static final Set<IpAddress> DHCP_SERVER_IPS = ImmutableSet.of(SERVER_IP, SERVER_IP_V6);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700212 private static final HostId SERVER_HOST_ID = HostId.hostId(SERVER_MAC, SERVER_VLAN);
Charles Chand988c282017-09-12 17:09:32 -0700213 private static final Host SERVER_HOST = new DefaultHost(Dhcp4HandlerImpl.PROVIDER_ID,
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700214 SERVER_HOST_ID,
215 SERVER_MAC,
216 SERVER_VLAN,
217 SERVER_LOCATION,
218 DHCP_SERVER_IPS);
219 private static final MacAddress SERVER_IFACE_MAC = MacAddress.valueOf("00:00:00:00:00:01");
Yi Tseng4025a102017-09-30 11:35:42 +0800220 private static final Interface SERVER_INTERFACE = createInterface("SERVER",
221 SERVER_CONNECT_POINT,
222 INTERFACE_IPS,
223 SERVER_IFACE_MAC,
224 SERVER_VLAN,
225 SERVER_VLAN_NATIVE);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700226
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700227 // Relay agent config
228 private static final Ip4Address RELAY_AGENT_IP = Ip4Address.valueOf("10.0.4.254");
229
Yi Tseng525ff402017-10-23 19:39:39 -0700230 private static final List<TrafficSelector> DHCP_SELECTORS = buildClientDhcpSelectors();
231
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700232 // Components
233 private static final ApplicationId APP_ID = TestApplicationId.create(DhcpRelayManager.DHCP_RELAY_APP);
Yi Tseng483ac6f2017-08-02 15:03:31 -0700234 private static final DefaultDhcpRelayConfig CONFIG = new MockDefaultDhcpRelayConfig();
Kalhee Kim45fede42017-09-05 19:05:06 +0000235 private static final IndirectDhcpRelayConfig CONFIG_INDIRECT = new MockIndirectDhcpRelayConfig();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700236 private static final Set<Interface> INTERFACES = ImmutableSet.of(
237 CLIENT_INTERFACE,
238 CLIENT2_INTERFACE,
Yi Tsengaa417a62017-09-08 17:22:51 -0700239 SERVER_INTERFACE,
240 CLIENT_DH_INTERFACE
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700241 );
Yi Tseng440e2b72017-08-24 14:47:34 -0700242 private static final String NON_ONOS_CID = "Non-ONOS circuit ID";
Yi Tseng51f1be92017-09-01 17:24:57 -0700243 private static final VlanId IGNORED_VLAN = VlanId.vlanId("100");
244 private static final int IGNORE_CONTROL_PRIORITY = PacketPriority.CONTROL.priorityValue() + 1000;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700245
246 private DhcpRelayManager manager;
247 private MockPacketService packetService;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700248 private MockRouteStore mockRouteStore;
249 private MockDhcpRelayStore mockDhcpRelayStore;
Yi Tsengaa417a62017-09-08 17:22:51 -0700250 private HostProviderService mockHostProviderService;
Yi Tseng525ff402017-10-23 19:39:39 -0700251 private FlowObjectiveService flowObjectiveService;
252 private DeviceService deviceService;
253 private Dhcp4HandlerImpl v4Handler;
254 private Dhcp6HandlerImpl v6Handler;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700255
Yi Tseng4025a102017-09-30 11:35:42 +0800256 private static Interface createInterface(String name, ConnectPoint connectPoint,
257 List<InterfaceIpAddress> interfaceIps,
258 MacAddress macAddress,
259 VlanId vlanId,
260 VlanId vlanNative) {
261
262 if (vlanId.equals(VlanId.NONE)) {
263 return new Interface(name, connectPoint, interfaceIps, macAddress, vlanId,
264 null, null, vlanNative);
265 } else {
266 return new Interface(name, connectPoint, interfaceIps, macAddress, vlanId,
267 null, ImmutableSet.of(vlanId), null);
268 }
269 }
270
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700271 @Before
272 public void setup() {
273 manager = new DhcpRelayManager();
274 manager.cfgService = createNiceMock(NetworkConfigRegistry.class);
275
Yi Tseng483ac6f2017-08-02 15:03:31 -0700276 expect(manager.cfgService.getConfig(APP_ID, DefaultDhcpRelayConfig.class))
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700277 .andReturn(CONFIG)
278 .anyTimes();
279
Yi Tseng483ac6f2017-08-02 15:03:31 -0700280 expect(manager.cfgService.getConfig(APP_ID, IndirectDhcpRelayConfig.class))
Kalhee Kim45fede42017-09-05 19:05:06 +0000281 .andReturn(CONFIG_INDIRECT)
Yi Tseng483ac6f2017-08-02 15:03:31 -0700282 .anyTimes();
283
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700284 manager.coreService = createNiceMock(CoreService.class);
285 expect(manager.coreService.registerApplication(anyString()))
286 .andReturn(APP_ID).anyTimes();
287
288 manager.hostService = createNiceMock(HostService.class);
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700289 expect(manager.hostService.getHostsByIp(anyObject())).andReturn(ImmutableSet.of(SERVER_HOST)).anyTimes();
290 expect(manager.hostService.getHost(OUTER_RELAY_HOST_ID)).andReturn(OUTER_RELAY_HOST).anyTimes();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700291
292 packetService = new MockPacketService();
293 manager.packetService = packetService;
294 manager.compCfgService = createNiceMock(ComponentConfigService.class);
Yi Tseng525ff402017-10-23 19:39:39 -0700295 deviceService = createNiceMock(DeviceService.class);
Yi Tseng127ffe52017-09-12 15:55:17 -0700296
297 Device device = createNiceMock(Device.class);
298 expect(device.is(Pipeliner.class)).andReturn(true).anyTimes();
299
Yi Tseng525ff402017-10-23 19:39:39 -0700300 expect(deviceService.getDevice(DEV_1_ID)).andReturn(device).anyTimes();
301 expect(deviceService.getDevice(DEV_2_ID)).andReturn(device).anyTimes();
302 replay(deviceService, device);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700303
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700304 mockRouteStore = new MockRouteStore();
305 mockDhcpRelayStore = new MockDhcpRelayStore();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700306 manager.dhcpRelayStore = mockDhcpRelayStore;
Yi Tseng525ff402017-10-23 19:39:39 -0700307 manager.deviceService = deviceService;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700308
309 manager.interfaceService = new MockInterfaceService();
Yi Tseng525ff402017-10-23 19:39:39 -0700310 flowObjectiveService = EasyMock.niceMock(FlowObjectiveService.class);
Yi Tsengaa417a62017-09-08 17:22:51 -0700311 mockHostProviderService = createNiceMock(HostProviderService.class);
Yi Tseng525ff402017-10-23 19:39:39 -0700312 v4Handler = new Dhcp4HandlerImpl();
Yi Tsengaa417a62017-09-08 17:22:51 -0700313 v4Handler.providerService = mockHostProviderService;
Yi Tseng51301292017-07-28 13:02:59 -0700314 v4Handler.dhcpRelayStore = mockDhcpRelayStore;
315 v4Handler.hostService = manager.hostService;
Yi Tseng51301292017-07-28 13:02:59 -0700316 v4Handler.interfaceService = manager.interfaceService;
317 v4Handler.packetService = manager.packetService;
318 v4Handler.routeStore = mockRouteStore;
Yi Tseng525ff402017-10-23 19:39:39 -0700319 v4Handler.coreService = createNiceMock(CoreService.class);
320 v4Handler.flowObjectiveService = flowObjectiveService;
321 v4Handler.appId = TestApplicationId.create(Dhcp4HandlerImpl.DHCP_V4_RELAY_APP);
322 v4Handler.deviceService = deviceService;
Yi Tseng51301292017-07-28 13:02:59 -0700323 manager.v4Handler = v4Handler;
324
Yi Tseng525ff402017-10-23 19:39:39 -0700325 v6Handler = new Dhcp6HandlerImpl();
Kalhee Kim45fede42017-09-05 19:05:06 +0000326 v6Handler.dhcpRelayStore = mockDhcpRelayStore;
327 v6Handler.hostService = manager.hostService;
Kalhee Kim45fede42017-09-05 19:05:06 +0000328 v6Handler.interfaceService = manager.interfaceService;
329 v6Handler.packetService = manager.packetService;
330 v6Handler.routeStore = mockRouteStore;
Yi Tsengaa417a62017-09-08 17:22:51 -0700331 v6Handler.providerService = mockHostProviderService;
Yi Tseng525ff402017-10-23 19:39:39 -0700332 v6Handler.coreService = createNiceMock(CoreService.class);
333 v6Handler.flowObjectiveService = flowObjectiveService;
334 v6Handler.appId = TestApplicationId.create(Dhcp6HandlerImpl.DHCP_V6_RELAY_APP);
335 v6Handler.deviceService = deviceService;
Yi Tseng483ac6f2017-08-02 15:03:31 -0700336 manager.v6Handler = v6Handler;
337
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700338 // properties
339 Dictionary<String, Object> dictionary = createNiceMock(Dictionary.class);
340 expect(dictionary.get("arpEnabled")).andReturn(true).anyTimes();
341 ComponentContext context = createNiceMock(ComponentContext.class);
342 expect(context.getProperties()).andReturn(dictionary).anyTimes();
343
Yi Tseng4025a102017-09-30 11:35:42 +0800344 replay(manager.cfgService, manager.coreService, manager.hostService,
345 manager.compCfgService, dictionary, context);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700346 manager.activate(context);
347 }
348
349 @After
350 public void tearDown() {
351 manager.deactivate();
352 }
353
354 /**
355 * Relay a DHCP packet without option 82.
356 * Should add new host to host store after dhcp ack.
357 */
358 @Test
359 public void relayDhcpWithoutAgentInfo() {
Yi Tsengaa417a62017-09-08 17:22:51 -0700360 replay(mockHostProviderService);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700361 // send request
362 packetService.processPacket(new TestDhcpRequestPacketContext(CLIENT_MAC,
363 CLIENT_VLAN,
364 CLIENT_CP,
365 INTERFACE_IP.ipAddress().getIp4Address(),
366 false));
Yi Tsengaa417a62017-09-08 17:22:51 -0700367 // won't trigger the host provider service
368 verify(mockHostProviderService);
369 reset(mockHostProviderService);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700370
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700371 assertEquals(0, mockRouteStore.routes.size());
372
Yi Tsengaa417a62017-09-08 17:22:51 -0700373 HostId expectHostId = HostId.hostId(CLIENT_MAC, CLIENT_VLAN);
374 Capture<HostDescription> capturedHostDesc = newCapture();
375 mockHostProviderService.hostDetected(eq(expectHostId), capture(capturedHostDesc), eq(false));
376 replay(mockHostProviderService);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700377 // send ack
378 packetService.processPacket(new TestDhcpAckPacketContext(CLIENT_CP, CLIENT_MAC,
379 CLIENT_VLAN, INTERFACE_IP.ipAddress().getIp4Address(),
380 false));
Yi Tsengaa417a62017-09-08 17:22:51 -0700381 verify(mockHostProviderService);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700382 assertEquals(0, mockRouteStore.routes.size());
383
Yi Tsengaa417a62017-09-08 17:22:51 -0700384 HostDescription host = capturedHostDesc.getValue();
385 assertEquals(false, host.configured());
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700386 assertEquals(CLIENT_CP.deviceId(), host.location().elementId());
387 assertEquals(CLIENT_CP.port(), host.location().port());
Yi Tsengaa417a62017-09-08 17:22:51 -0700388 assertEquals(1, host.ipAddress().size());
389 assertEquals(IP_FOR_CLIENT, host.ipAddress().iterator().next());
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700390 }
391
392 /**
393 * Relay a DHCP packet with option 82 (Indirectly connected host).
394 */
395 @Test
396 public void relayDhcpWithAgentInfo() {
Yi Tsengaa417a62017-09-08 17:22:51 -0700397 replay(mockHostProviderService);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700398 // Assume outer dhcp relay agent exists in store already
399 // send request
400 packetService.processPacket(new TestDhcpRequestPacketContext(CLIENT2_MAC,
401 CLIENT2_VLAN,
402 CLIENT2_CP,
403 INTERFACE_IP.ipAddress().getIp4Address(),
404 true));
Yi Tsengaa417a62017-09-08 17:22:51 -0700405 // No routes
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700406 assertEquals(0, mockRouteStore.routes.size());
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700407 // send ack
408 packetService.processPacket(new TestDhcpAckPacketContext(CLIENT2_CP,
409 CLIENT2_MAC,
410 CLIENT2_VLAN,
411 INTERFACE_IP.ipAddress().getIp4Address(),
412 true));
413
Yi Tsengaa417a62017-09-08 17:22:51 -0700414 // won't trigger the host provider service
415 verify(mockHostProviderService);
416 reset(mockHostProviderService);
417
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700418 assertEquals(1, mockRouteStore.routes.size());
419
420 Route route = mockRouteStore.routes.get(0);
421 assertEquals(OUTER_RELAY_IP, route.nextHop());
422 assertEquals(IP_FOR_CLIENT.toIpPrefix(), route.prefix());
423 assertEquals(Route.Source.STATIC, route.source());
424 }
425
426 @Test
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700427 public void testWithRelayAgentConfig() throws DeserializationException {
428 manager.v4Handler
429 .setDefaultDhcpServerConfigs(ImmutableList.of(new MockDhcpServerConfig(RELAY_AGENT_IP)));
Yi Tseng4f2a0462017-08-31 11:21:00 -0700430 manager.v4Handler
431 .setIndirectDhcpServerConfigs(ImmutableList.of(new MockDhcpServerConfig(RELAY_AGENT_IP)));
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700432 packetService.processPacket(new TestDhcpRequestPacketContext(CLIENT2_MAC,
433 CLIENT2_VLAN,
434 CLIENT2_CP,
435 INTERFACE_IP.ipAddress().getIp4Address(),
436 true));
437 OutboundPacket outPacket = packetService.emittedPacket;
438 byte[] outData = outPacket.data().array();
439 Ethernet eth = Ethernet.deserializer().deserialize(outData, 0, outData.length);
440 IPv4 ip = (IPv4) eth.getPayload();
441 UDP udp = (UDP) ip.getPayload();
442 DHCP dhcp = (DHCP) udp.getPayload();
443 assertEquals(RELAY_AGENT_IP.toInt(), dhcp.getGatewayIPAddress());
444 }
445
446 @Test
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700447 public void testArpRequest() throws Exception {
448 packetService.processPacket(new TestArpRequestPacketContext(CLIENT_INTERFACE));
Ray Milkeyc108a6b2017-08-23 15:23:50 -0700449 OutboundPacket outboundPacket = packetService.emittedPacket;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700450 byte[] outPacketData = outboundPacket.data().array();
451 Ethernet eth = Ethernet.deserializer().deserialize(outPacketData, 0, outPacketData.length);
452
453 assertEquals(eth.getEtherType(), Ethernet.TYPE_ARP);
454 ARP arp = (ARP) eth.getPayload();
455 assertArrayEquals(arp.getSenderHardwareAddress(), CLIENT_INTERFACE.mac().toBytes());
456 }
457
Yi Tseng51f1be92017-09-01 17:24:57 -0700458 /**
459 * Ignores specific vlans from specific devices if config.
460 *
461 * @throws Exception the exception from this test
462 */
463 @Test
464 public void testIgnoreVlan() throws Exception {
465 ObjectMapper om = new ObjectMapper();
466 JsonNode json = om.readTree(Resources.getResource(CONFIG_FILE_PATH));
467 IgnoreDhcpConfig config = new IgnoreDhcpConfig();
468 json = json.path("apps").path(DHCP_RELAY_APP).path(IgnoreDhcpConfig.KEY);
469 config.init(APP_ID, IgnoreDhcpConfig.KEY, json, om, null);
470
471 Capture<Objective> capturedFromDev1 = newCapture(CaptureType.ALL);
Yi Tseng525ff402017-10-23 19:39:39 -0700472 flowObjectiveService.apply(eq(DEV_1_ID), capture(capturedFromDev1));
Yi Tseng127ffe52017-09-12 15:55:17 -0700473 expectLastCall().times(DHCP_SELECTORS.size());
Yi Tseng51f1be92017-09-01 17:24:57 -0700474 Capture<Objective> capturedFromDev2 = newCapture(CaptureType.ALL);
Yi Tseng525ff402017-10-23 19:39:39 -0700475 flowObjectiveService.apply(eq(DEV_2_ID), capture(capturedFromDev2));
Yi Tseng127ffe52017-09-12 15:55:17 -0700476 expectLastCall().times(DHCP_SELECTORS.size());
Yi Tseng525ff402017-10-23 19:39:39 -0700477 replay(flowObjectiveService);
Yi Tseng51f1be92017-09-01 17:24:57 -0700478 manager.updateConfig(config);
Yi Tseng525ff402017-10-23 19:39:39 -0700479 verify(flowObjectiveService);
Yi Tseng51f1be92017-09-01 17:24:57 -0700480
481 List<Objective> objectivesFromDev1 = capturedFromDev1.getValues();
482 List<Objective> objectivesFromDev2 = capturedFromDev2.getValues();
483
484 assertTrue(objectivesFromDev1.containsAll(objectivesFromDev2));
485 assertTrue(objectivesFromDev2.containsAll(objectivesFromDev1));
Yi Tseng525ff402017-10-23 19:39:39 -0700486 TrafficTreatment dropTreatment = DefaultTrafficTreatment.builder().wipeDeferred().build();
Yi Tseng51f1be92017-09-01 17:24:57 -0700487
488 for (int index = 0; index < objectivesFromDev1.size(); index++) {
489 TrafficSelector selector =
Yi Tseng525ff402017-10-23 19:39:39 -0700490 DefaultTrafficSelector.builder(DHCP_SELECTORS.get(index))
Yi Tseng51f1be92017-09-01 17:24:57 -0700491 .matchVlanId(IGNORED_VLAN)
492 .build();
493 ForwardingObjective fwd = (ForwardingObjective) objectivesFromDev1.get(index);
494 assertEquals(selector, fwd.selector());
495 assertEquals(dropTreatment, fwd.treatment());
496 assertEquals(IGNORE_CONTROL_PRIORITY, fwd.priority());
497 assertEquals(ForwardingObjective.Flag.VERSATILE, fwd.flag());
498 assertEquals(Objective.Operation.ADD, fwd.op());
Yi Tseng127ffe52017-09-12 15:55:17 -0700499 fwd.context().ifPresent(ctx -> {
500 ctx.onSuccess(fwd);
501 });
Yi Tseng51f1be92017-09-01 17:24:57 -0700502 }
Yi Tseng127ffe52017-09-12 15:55:17 -0700503 objectivesFromDev2.forEach(obj -> obj.context().ifPresent(ctx -> ctx.onSuccess(obj)));
Yi Tseng525ff402017-10-23 19:39:39 -0700504 assertEquals(2, v4Handler.ignoredVlans.size());
505 assertEquals(2, v6Handler.ignoredVlans.size());
Yi Tseng51f1be92017-09-01 17:24:57 -0700506 }
507
508 /**
509 * "IgnoreVlan" policy should be removed when the config removed.
510 */
511 @Test
512 public void testRemoveIgnoreVlan() {
Yi Tseng525ff402017-10-23 19:39:39 -0700513 v4Handler.ignoredVlans.put(DEV_1_ID, IGNORED_VLAN);
514 v4Handler.ignoredVlans.put(DEV_2_ID, IGNORED_VLAN);
515 v6Handler.ignoredVlans.put(DEV_1_ID, IGNORED_VLAN);
516 v6Handler.ignoredVlans.put(DEV_2_ID, IGNORED_VLAN);
Yi Tseng51f1be92017-09-01 17:24:57 -0700517 IgnoreDhcpConfig config = new IgnoreDhcpConfig();
518
519 Capture<Objective> capturedFromDev1 = newCapture(CaptureType.ALL);
Yi Tseng525ff402017-10-23 19:39:39 -0700520 flowObjectiveService.apply(eq(DEV_1_ID), capture(capturedFromDev1));
Yi Tseng127ffe52017-09-12 15:55:17 -0700521 expectLastCall().times(DHCP_SELECTORS.size());
Yi Tseng51f1be92017-09-01 17:24:57 -0700522 Capture<Objective> capturedFromDev2 = newCapture(CaptureType.ALL);
Yi Tseng525ff402017-10-23 19:39:39 -0700523 flowObjectiveService.apply(eq(DEV_2_ID), capture(capturedFromDev2));
Yi Tseng127ffe52017-09-12 15:55:17 -0700524 expectLastCall().times(DHCP_SELECTORS.size());
Yi Tseng525ff402017-10-23 19:39:39 -0700525 replay(flowObjectiveService);
Yi Tseng51f1be92017-09-01 17:24:57 -0700526 manager.removeConfig(config);
Yi Tseng525ff402017-10-23 19:39:39 -0700527 verify(flowObjectiveService);
Yi Tseng51f1be92017-09-01 17:24:57 -0700528
529 List<Objective> objectivesFromDev1 = capturedFromDev1.getValues();
530 List<Objective> objectivesFromDev2 = capturedFromDev2.getValues();
531
532 assertTrue(objectivesFromDev1.containsAll(objectivesFromDev2));
533 assertTrue(objectivesFromDev2.containsAll(objectivesFromDev1));
Yi Tseng525ff402017-10-23 19:39:39 -0700534 TrafficTreatment dropTreatment = DefaultTrafficTreatment.builder().wipeDeferred().build();
Yi Tseng51f1be92017-09-01 17:24:57 -0700535
536 for (int index = 0; index < objectivesFromDev1.size(); index++) {
537 TrafficSelector selector =
Yi Tseng525ff402017-10-23 19:39:39 -0700538 DefaultTrafficSelector.builder(DHCP_SELECTORS.get(index))
Yi Tseng51f1be92017-09-01 17:24:57 -0700539 .matchVlanId(IGNORED_VLAN)
540 .build();
541 ForwardingObjective fwd = (ForwardingObjective) objectivesFromDev1.get(index);
542 assertEquals(selector, fwd.selector());
543 assertEquals(dropTreatment, fwd.treatment());
544 assertEquals(IGNORE_CONTROL_PRIORITY, fwd.priority());
545 assertEquals(ForwardingObjective.Flag.VERSATILE, fwd.flag());
546 assertEquals(Objective.Operation.REMOVE, fwd.op());
Yi Tseng127ffe52017-09-12 15:55:17 -0700547 fwd.context().ifPresent(ctx -> {
548 ctx.onSuccess(fwd);
549 });
Yi Tseng51f1be92017-09-01 17:24:57 -0700550 }
Yi Tseng127ffe52017-09-12 15:55:17 -0700551 objectivesFromDev2.forEach(obj -> obj.context().ifPresent(ctx -> ctx.onSuccess(obj)));
Yi Tseng525ff402017-10-23 19:39:39 -0700552 assertEquals(0, v4Handler.ignoredVlans.size());
553 assertEquals(0, v6Handler.ignoredVlans.size());
Yi Tseng51f1be92017-09-01 17:24:57 -0700554 }
555
Kalhee Kim45fede42017-09-05 19:05:06 +0000556 /**
Yi Tseng127ffe52017-09-12 15:55:17 -0700557 * Should ignore ignore rules installation when device not available.
558 */
559 @Test
560 public void testIgnoreUnknownDevice() throws IOException {
561 reset(manager.deviceService);
562 Device device = createNiceMock(Device.class);
563 expect(device.is(Pipeliner.class)).andReturn(true).anyTimes();
564
565 expect(manager.deviceService.getDevice(DEV_1_ID)).andReturn(device).anyTimes();
566 expect(manager.deviceService.getDevice(DEV_2_ID)).andReturn(null).anyTimes();
567
568 ObjectMapper om = new ObjectMapper();
569 JsonNode json = om.readTree(Resources.getResource(CONFIG_FILE_PATH));
570 IgnoreDhcpConfig config = new IgnoreDhcpConfig();
571 json = json.path("apps").path(DHCP_RELAY_APP).path(IgnoreDhcpConfig.KEY);
572 config.init(APP_ID, IgnoreDhcpConfig.KEY, json, om, null);
573
574 Capture<Objective> capturedFromDev1 = newCapture(CaptureType.ALL);
Yi Tseng525ff402017-10-23 19:39:39 -0700575 flowObjectiveService.apply(eq(DEV_1_ID), capture(capturedFromDev1));
Yi Tseng127ffe52017-09-12 15:55:17 -0700576 expectLastCall().times(DHCP_SELECTORS.size());
Yi Tseng525ff402017-10-23 19:39:39 -0700577 replay(flowObjectiveService, manager.deviceService, device);
Yi Tseng127ffe52017-09-12 15:55:17 -0700578
579 manager.updateConfig(config);
580 capturedFromDev1.getValues().forEach(obj -> obj.context().ifPresent(ctx -> ctx.onSuccess(obj)));
581
Yi Tseng525ff402017-10-23 19:39:39 -0700582 assertEquals(1, v4Handler.ignoredVlans.size());
583 assertEquals(1, v6Handler.ignoredVlans.size());
Yi Tseng127ffe52017-09-12 15:55:17 -0700584 }
585
586 /**
587 * Should try install ignore rules when device comes up.
588 */
589 @Test
590 public void testInstallIgnoreRuleWhenDeviceComesUp() throws IOException {
591 ObjectMapper om = new ObjectMapper();
592 JsonNode json = om.readTree(Resources.getResource(CONFIG_FILE_PATH));
593 IgnoreDhcpConfig config = new IgnoreDhcpConfig();
594 json = json.path("apps").path(DHCP_RELAY_APP).path(IgnoreDhcpConfig.KEY);
595 config.init(APP_ID, IgnoreDhcpConfig.KEY, json, om, null);
596
Yi Tseng525ff402017-10-23 19:39:39 -0700597 reset(manager.cfgService, flowObjectiveService, manager.deviceService);
Yi Tseng127ffe52017-09-12 15:55:17 -0700598 expect(manager.cfgService.getConfig(APP_ID, IgnoreDhcpConfig.class))
599 .andReturn(config).anyTimes();
600
601 Device device = createNiceMock(Device.class);
602 expect(device.is(Pipeliner.class)).andReturn(true).anyTimes();
603 expect(device.id()).andReturn(DEV_1_ID).anyTimes();
604 expect(manager.deviceService.getDevice(DEV_1_ID)).andReturn(device).anyTimes();
605 DeviceEvent event = new DeviceEvent(DeviceEvent.Type.DEVICE_ADDED, device);
606 Capture<Objective> capturedFromDev1 = newCapture(CaptureType.ALL);
Yi Tseng525ff402017-10-23 19:39:39 -0700607 flowObjectiveService.apply(eq(DEV_1_ID), capture(capturedFromDev1));
Yi Tseng127ffe52017-09-12 15:55:17 -0700608 expectLastCall().times(DHCP_SELECTORS.size());
Yi Tseng525ff402017-10-23 19:39:39 -0700609 replay(manager.cfgService, flowObjectiveService, manager.deviceService, device);
Yi Tseng127ffe52017-09-12 15:55:17 -0700610 manager.deviceListener.event(event);
611 capturedFromDev1.getValues().forEach(obj -> obj.context().ifPresent(ctx -> ctx.onSuccess(obj)));
Yi Tseng525ff402017-10-23 19:39:39 -0700612 assertEquals(1, v4Handler.ignoredVlans.size());
613 assertEquals(1, v6Handler.ignoredVlans.size());
Yi Tseng127ffe52017-09-12 15:55:17 -0700614 }
615
616 /**
Kalhee Kim45fede42017-09-05 19:05:06 +0000617 * Relay a DHCP6 packet without relay option
618 * Note: Should add new host to host store after dhcp ack.
619 */
620 @Test
621 public void relayDhcp6WithoutAgentInfo() {
Yi Tsengaa417a62017-09-08 17:22:51 -0700622 replay(mockHostProviderService);
Kalhee Kim45fede42017-09-05 19:05:06 +0000623 // send request
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000624 packetService.processPacket(new TestDhcp6RequestPacketContext(DHCP6.MsgType.REQUEST.value(),
625 CLIENT_MAC,
626 CLIENT_VLAN,
Kalhee Kim45fede42017-09-05 19:05:06 +0000627 CLIENT_CP,
628 INTERFACE_IP_V6.ipAddress().getIp6Address(),
629 0));
630
Yi Tsengaa417a62017-09-08 17:22:51 -0700631 verify(mockHostProviderService);
632 reset(mockHostProviderService);
Kalhee Kim45fede42017-09-05 19:05:06 +0000633 assertEquals(0, mockRouteStore.routes.size());
634
Yi Tsengaa417a62017-09-08 17:22:51 -0700635 Capture<HostDescription> capturedHostDesc = newCapture();
636 mockHostProviderService.hostDetected(eq(HostId.hostId(CLIENT_MAC, CLIENT_VLAN)),
637 capture(capturedHostDesc), eq(false));
638 replay(mockHostProviderService);
Kalhee Kim45fede42017-09-05 19:05:06 +0000639 // send reply
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000640 packetService.processPacket(new TestDhcp6ReplyPacketContext(DHCP6.MsgType.REPLY.value(),
641 CLIENT_CP, CLIENT_MAC,
Kalhee Kim45fede42017-09-05 19:05:06 +0000642 CLIENT_VLAN,
643 INTERFACE_IP_V6.ipAddress().getIp6Address(),
644 0));
Yi Tsengaa417a62017-09-08 17:22:51 -0700645 verify(mockHostProviderService);
Kalhee Kim45fede42017-09-05 19:05:06 +0000646 assertEquals(0, mockRouteStore.routes.size());
647
Yi Tsengaa417a62017-09-08 17:22:51 -0700648 HostDescription host = capturedHostDesc.getValue();
Kalhee Kim45fede42017-09-05 19:05:06 +0000649 assertEquals(CLIENT_VLAN, host.vlan());
650 assertEquals(CLIENT_CP.deviceId(), host.location().elementId());
651 assertEquals(CLIENT_CP.port(), host.location().port());
Yi Tsengaa417a62017-09-08 17:22:51 -0700652 assertEquals(1, host.ipAddress().size());
653 assertEquals(IP_FOR_CLIENT_V6, host.ipAddress().iterator().next());
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000654
655 // send release
656 packetService.processPacket(new TestDhcp6RequestPacketContext(DHCP6.MsgType.RELEASE.value(),
657 CLIENT_MAC,
658 CLIENT_VLAN,
659 CLIENT_CP,
660 INTERFACE_IP_V6.ipAddress().getIp6Address(),
661 0));
662
663 assertEquals(null, manager.hostService.getHost(HostId.hostId(CLIENT_MAC, CLIENT_VLAN)));
Kalhee Kim45fede42017-09-05 19:05:06 +0000664 }
665
666 /**
667 * Relay a DHCP6 packet with Relay Message opion (Indirectly connected host).
668 */
669 @Test
670 public void relayDhcp6WithAgentInfo() {
Yi Tsengaa417a62017-09-08 17:22:51 -0700671 replay(mockHostProviderService);
Kalhee Kim45fede42017-09-05 19:05:06 +0000672 // Assume outer dhcp6 relay agent exists in store already
673 // send request
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000674 packetService.processPacket(new TestDhcp6RequestPacketContext(DHCP6.MsgType.REQUEST.value(),
675 CLIENT2_MAC,
676 CLIENT2_VLAN,
677 CLIENT2_CP,
678 OUTER_RELAY_IP_V6,
679 1));
680
681 assertEquals(0, mockRouteStore.routes.size());
682
683 // send reply
684 packetService.processPacket(new TestDhcp6ReplyPacketContext(DHCP6.MsgType.REPLY.value(), CLIENT2_CP,
685 CLIENT2_MAC,
686 CLIENT2_VLAN,
687 OUTER_RELAY_IP_V6,
688 1));
689
690 // won't trigger the host provider service
691 verify(mockHostProviderService);
692 reset(mockHostProviderService);
693 assertEquals(2, mockRouteStore.routes.size()); // ipAddress and prefix
694
695 Route aRoute = mockRouteStore.routes.stream()
696 .filter(rt -> rt.prefix().contains(IP_FOR_CLIENT_V6))
697 .findFirst()
698 .orElse(null);
699 assertNotEquals(null, aRoute);
700
701 aRoute = mockRouteStore.routes.stream()
702 .filter(rt -> rt.prefix().contains(PREFIX_FOR_CLIENT_V6))
703 .findFirst()
704 .orElse(null);
705 assertNotEquals(null, aRoute);
706
707 // send release msg
708 packetService.processPacket(new TestDhcp6RequestPacketContext(DHCP6.MsgType.RELEASE.value(),
709 CLIENT2_MAC,
710 CLIENT2_VLAN,
711 CLIENT2_CP,
712 OUTER_RELAY_IP_V6,
713 1));
714
715 aRoute = mockRouteStore.routes.stream()
716 .filter(rt -> rt.prefix().contains(IP_FOR_CLIENT_V6))
717 .findFirst()
718 .orElse(null);
719 assertEquals(null, aRoute);
720
721 aRoute = mockRouteStore.routes.stream()
722 .filter(rt -> rt.prefix().contains(PREFIX_FOR_CLIENT_V6))
723 .findFirst()
724 .orElse(null);
725 assertEquals(null, aRoute);
726
727 assertEquals(0, mockRouteStore.routes.size());
728
729 }
730
731 /**
732 * Relay a DHCP6 packet with Relay Message opion (Indirectly connected host) and server responded
733 * with vlan differnt from client interface vlan.
734 */
735 @Test
736 public void relayDhcp6WithAgentInfoWrongVlan() {
737 replay(mockHostProviderService);
738 // Assume outer dhcp6 relay agent exists in store already
739 // send request
740 packetService.processPacket(new TestDhcp6RequestPacketContext(DHCP6.MsgType.REQUEST.value(),
741 CLIENT2_MAC,
Kalhee Kim45fede42017-09-05 19:05:06 +0000742 CLIENT2_VLAN,
743 CLIENT2_CP,
744 INTERFACE_IP_V6.ipAddress().getIp6Address(),
745 1));
746
Kalhee Kim45fede42017-09-05 19:05:06 +0000747 assertEquals(0, mockRouteStore.routes.size());
748
749 // send reply
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000750 packetService.processPacket(new TestDhcp6ReplyPacketContext(DHCP6.MsgType.REPLY.value(),
751 CLIENT2_CP,
Kalhee Kim45fede42017-09-05 19:05:06 +0000752 CLIENT2_MAC,
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000753 CLIENT_BOGUS_VLAN, // mismatch
Kalhee Kim45fede42017-09-05 19:05:06 +0000754 INTERFACE_IP_V6.ipAddress().getIp6Address(),
755 1));
756
Yi Tsengaa417a62017-09-08 17:22:51 -0700757 // won't trigger the host provider service
758 verify(mockHostProviderService);
759 reset(mockHostProviderService);
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000760 assertEquals(0, mockRouteStore.routes.size()); // ipAddress and prefix
Kalhee Kim45fede42017-09-05 19:05:06 +0000761
Kalhee Kim45fede42017-09-05 19:05:06 +0000762 }
Yi Tsengaa417a62017-09-08 17:22:51 -0700763
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000764
Yi Tsengaa417a62017-09-08 17:22:51 -0700765 @Test
766 public void testDhcp4DualHome() {
767 PacketContext packetContext =
768 new TestDhcpAckPacketContext(CLIENT_DH_CP, CLIENT_MAC, CLIENT_VLAN,
769 INTERFACE_IP.ipAddress().getIp4Address(),
770 false);
771 reset(manager.hostService);
772 expect(manager.hostService.getHost(CLIENT_HOST_ID)).andReturn(EXISTS_HOST).anyTimes();
773 Capture<HostDescription> capturedHostDesc = newCapture();
774 mockHostProviderService.hostDetected(eq(CLIENT_HOST_ID), capture(capturedHostDesc), eq(false));
775 replay(mockHostProviderService, manager.hostService);
776 packetService.processPacket(packetContext);
777 verify(mockHostProviderService);
778
779 HostDescription hostDesc = capturedHostDesc.getValue();
780 Set<HostLocation> hostLocations = hostDesc.locations();
781 assertEquals(2, hostLocations.size());
782 assertTrue(hostLocations.contains(CLIENT_LOCATION));
783 assertTrue(hostLocations.contains(CLIENT_DH_LOCATION));
784 }
785
786 @Test
787 public void testDhcp6DualHome() {
788 PacketContext packetContext =
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000789 new TestDhcp6ReplyPacketContext(DHCP6.MsgType.REPLY.value(),
790 CLIENT_DH_CP, CLIENT_MAC, CLIENT_VLAN,
Yi Tsengaa417a62017-09-08 17:22:51 -0700791 INTERFACE_IP_V6.ipAddress().getIp6Address(),
792 0);
793 reset(manager.hostService);
794 expect(manager.hostService.getHostsByIp(CLIENT_LL_IP_V6)).andReturn(ImmutableSet.of(EXISTS_HOST)).anyTimes();
795
796 // FIXME: currently DHCPv6 has a bug, we can't get correct vlan of client......
797 // XXX: The vlan relied from DHCP6 handler might be wrong, do hack here
798 HostId hostId = HostId.hostId(CLIENT_MAC, VlanId.NONE);
799 expect(manager.hostService.getHost(hostId)).andReturn(EXISTS_HOST).anyTimes();
800
801 // XXX: sometimes this will work, sometimes not
802 expect(manager.hostService.getHost(CLIENT_HOST_ID)).andReturn(EXISTS_HOST).anyTimes();
803
804 Capture<HostDescription> capturedHostDesc = newCapture();
805
806 // XXX: also a hack here
807 mockHostProviderService.hostDetected(eq(hostId), capture(capturedHostDesc), eq(false));
808 expectLastCall().anyTimes();
809
810 mockHostProviderService.hostDetected(eq(CLIENT_HOST_ID), capture(capturedHostDesc), eq(false));
811 expectLastCall().anyTimes();
812 replay(mockHostProviderService, manager.hostService);
813 packetService.processPacket(packetContext);
814 verify(mockHostProviderService);
815
816 HostDescription hostDesc = capturedHostDesc.getValue();
817 Set<HostLocation> hostLocations = hostDesc.locations();
818 assertEquals(2, hostLocations.size());
819 assertTrue(hostLocations.contains(CLIENT_LOCATION));
820 assertTrue(hostLocations.contains(CLIENT_DH_LOCATION));
821 }
822
Yi Tseng483ac6f2017-08-02 15:03:31 -0700823 private static class MockDefaultDhcpRelayConfig extends DefaultDhcpRelayConfig {
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700824 @Override
825 public boolean isValid() {
826 return true;
827 }
828
829 @Override
Yi Tseng483ac6f2017-08-02 15:03:31 -0700830 public List<DhcpServerConfig> dhcpServerConfigs() {
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700831 return ImmutableList.of(new MockDhcpServerConfig(null));
Yi Tseng483ac6f2017-08-02 15:03:31 -0700832 }
833 }
834
Kalhee Kim45fede42017-09-05 19:05:06 +0000835 private static class MockIndirectDhcpRelayConfig extends IndirectDhcpRelayConfig {
836 @Override
837 public boolean isValid() {
838 return true;
839 }
840
841 @Override
842 public List<DhcpServerConfig> dhcpServerConfigs() {
843 return ImmutableList.of(new MockDhcpServerConfig(null));
844 }
845 }
846
Yi Tseng483ac6f2017-08-02 15:03:31 -0700847 private static class MockDhcpServerConfig extends DhcpServerConfig {
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700848 Ip4Address relayAgentIp;
849
850 /**
851 * Create mocked version DHCP server config.
852 *
853 * @param relayAgentIp the relay agent Ip config; null if we don't need it
854 */
855 public MockDhcpServerConfig(Ip4Address relayAgentIp) {
856 this.relayAgentIp = relayAgentIp;
857 }
858
859 @Override
860 public Optional<Ip4Address> getRelayAgentIp4() {
861 return Optional.ofNullable(relayAgentIp);
862 }
863
Yi Tseng483ac6f2017-08-02 15:03:31 -0700864 @Override
865 public Optional<ConnectPoint> getDhcpServerConnectPoint() {
866 return Optional.of(SERVER_CONNECT_POINT);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700867 }
868
Yi Tseng483ac6f2017-08-02 15:03:31 -0700869 @Override
870 public Optional<Ip4Address> getDhcpServerIp4() {
871 return Optional.of(SERVER_IP);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700872 }
Kalhee Kim45fede42017-09-05 19:05:06 +0000873
874 @Override
875 public Optional<Ip4Address> getDhcpGatewayIp4() {
876 return Optional.of(GATEWAY_IP);
877 }
878
879 @Override
880 public Optional<Ip6Address> getDhcpServerIp6() {
881 return Optional.of(SERVER_IP_V6);
882 }
883
884 @Override
885 public Optional<Ip6Address> getDhcpGatewayIp6() {
886 return Optional.of(GATEWAY_IP_V6);
887 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700888 }
889
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700890 private class MockRouteStore extends RouteStoreAdapter {
891 private List<Route> routes = Lists.newArrayList();
892
893 @Override
894 public void updateRoute(Route route) {
895 routes.add(route);
896 }
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000897
898 @Override
899 public void removeRoute(Route route) {
900 routes.remove(route);
901 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700902 }
903
904 private class MockInterfaceService extends InterfaceServiceAdapter {
905
906 @Override
907 public Set<Interface> getInterfaces() {
908 return INTERFACES;
909 }
910
911 @Override
912 public Set<Interface> getInterfacesByIp(IpAddress ip) {
913 return INTERFACES.stream()
914 .filter(iface -> {
915 return iface.ipAddressesList().stream()
916 .anyMatch(ifaceIp -> ifaceIp.ipAddress().equals(ip));
917 })
918 .collect(Collectors.toSet());
919 }
920
921 @Override
922 public Set<Interface> getInterfacesByPort(ConnectPoint port) {
923 return INTERFACES.stream()
924 .filter(iface -> iface.connectPoint().equals(port))
925 .collect(Collectors.toSet());
926 }
927 }
928
929 private class MockDhcpRelayStore implements DhcpRelayStore {
930 StoreDelegate<DhcpRelayStoreEvent> delegate;
931 private Map<HostId, DhcpRecord> records = Maps.newHashMap();
932
933 @Override
934 public void updateDhcpRecord(HostId hostId, DhcpRecord dhcpRecord) {
935 records.put(hostId, dhcpRecord);
936 DhcpRelayStoreEvent event = new DhcpRelayStoreEvent(DhcpRelayStoreEvent.Type.UPDATED,
937 dhcpRecord);
938 if (delegate != null) {
939 delegate.notify(event);
940 }
941 }
942
943 @Override
944 public Optional<DhcpRecord> getDhcpRecord(HostId hostId) {
945 return Optional.ofNullable(records.get(hostId));
946 }
947
948 @Override
949 public Collection<DhcpRecord> getDhcpRecords() {
950 return records.values();
951 }
952
953 @Override
954 public Optional<DhcpRecord> removeDhcpRecord(HostId hostId) {
955 DhcpRecord dhcpRecord = records.remove(hostId);
956 if (dhcpRecord != null) {
957 DhcpRelayStoreEvent event = new DhcpRelayStoreEvent(DhcpRelayStoreEvent.Type.REMOVED,
958 dhcpRecord);
959 if (delegate != null) {
960 delegate.notify(event);
961 }
962 }
963 return Optional.ofNullable(dhcpRecord);
964 }
965
966 @Override
967 public void setDelegate(StoreDelegate<DhcpRelayStoreEvent> delegate) {
968 this.delegate = delegate;
969 }
970
971 @Override
972 public void unsetDelegate(StoreDelegate<DhcpRelayStoreEvent> delegate) {
973 this.delegate = null;
974 }
975
976 @Override
977 public boolean hasDelegate() {
978 return this.delegate != null;
979 }
980 }
981
982 private class MockPacketService extends PacketServiceAdapter {
983 Set<PacketProcessor> packetProcessors = Sets.newHashSet();
Ray Milkeyc108a6b2017-08-23 15:23:50 -0700984 OutboundPacket emittedPacket;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700985
986 @Override
987 public void addProcessor(PacketProcessor processor, int priority) {
988 packetProcessors.add(processor);
989 }
990
991 public void processPacket(PacketContext packetContext) {
992 packetProcessors.forEach(p -> p.process(packetContext));
993 }
994
995 @Override
996 public void emit(OutboundPacket packet) {
Ray Milkeyc108a6b2017-08-23 15:23:50 -0700997 this.emittedPacket = packet;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700998 }
999 }
1000
1001
1002
1003 /**
1004 * Generates DHCP REQUEST packet.
1005 */
1006 private class TestDhcpRequestPacketContext extends PacketContextAdapter {
1007
1008
1009 private InboundPacket inPacket;
1010
1011 public TestDhcpRequestPacketContext(MacAddress clientMac, VlanId vlanId,
1012 ConnectPoint clientCp,
1013 Ip4Address clientGwAddr,
1014 boolean withNonOnosRelayInfo) {
1015 super(0, null, null, false);
1016 byte[] dhcpMsgType = new byte[1];
1017 dhcpMsgType[0] = (byte) DHCP.MsgType.DHCPREQUEST.getValue();
1018
1019 DhcpOption dhcpOption = new DhcpOption();
1020 dhcpOption.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue());
1021 dhcpOption.setData(dhcpMsgType);
1022 dhcpOption.setLength((byte) 1);
1023 DhcpOption endOption = new DhcpOption();
1024 endOption.setCode(DHCP.DHCPOptionCode.OptionCode_END.getValue());
1025
1026 DHCP dhcp = new DHCP();
1027 dhcp.setHardwareType(DHCP.HWTYPE_ETHERNET);
1028 dhcp.setHardwareAddressLength((byte) 6);
1029 dhcp.setClientHardwareAddress(clientMac.toBytes());
1030 if (withNonOnosRelayInfo) {
1031 DhcpRelayAgentOption relayOption = new DhcpRelayAgentOption();
1032 DhcpOption circuitIdOption = new DhcpOption();
1033 CircuitId circuitId = new CircuitId("Custom option", VlanId.NONE);
1034 byte[] cid = circuitId.serialize();
1035 circuitIdOption.setCode(DhcpRelayAgentOption.RelayAgentInfoOptions.CIRCUIT_ID.getValue());
1036 circuitIdOption.setLength((byte) cid.length);
1037 circuitIdOption.setData(cid);
1038 relayOption.setCode(DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue());
1039 relayOption.addSubOption(circuitIdOption);
1040 dhcp.setOptions(ImmutableList.of(dhcpOption, relayOption, endOption));
1041 dhcp.setGatewayIPAddress(OUTER_RELAY_IP.getIp4Address().toInt());
1042 } else {
1043 dhcp.setOptions(ImmutableList.of(dhcpOption, endOption));
1044 }
1045
1046
1047 UDP udp = new UDP();
1048 udp.setPayload(dhcp);
1049 udp.setSourcePort(UDP.DHCP_CLIENT_PORT);
1050 udp.setDestinationPort(UDP.DHCP_SERVER_PORT);
1051
1052 IPv4 ipv4 = new IPv4();
1053 ipv4.setPayload(udp);
1054 ipv4.setDestinationAddress(SERVER_IP.toInt());
1055 ipv4.setSourceAddress(clientGwAddr.toInt());
1056
1057 Ethernet eth = new Ethernet();
1058 if (withNonOnosRelayInfo) {
1059 eth.setEtherType(Ethernet.TYPE_IPV4)
1060 .setVlanID(vlanId.toShort())
1061 .setSourceMACAddress(OUTER_RELAY_MAC)
1062 .setDestinationMACAddress(MacAddress.BROADCAST)
1063 .setPayload(ipv4);
1064 } else {
1065 eth.setEtherType(Ethernet.TYPE_IPV4)
1066 .setVlanID(vlanId.toShort())
1067 .setSourceMACAddress(clientMac)
1068 .setDestinationMACAddress(MacAddress.BROADCAST)
1069 .setPayload(ipv4);
1070 }
1071
1072 this.inPacket = new DefaultInboundPacket(clientCp, eth,
1073 ByteBuffer.wrap(eth.serialize()));
1074 }
1075
1076 @Override
1077 public InboundPacket inPacket() {
1078 return this.inPacket;
1079 }
1080 }
1081
1082 /**
1083 * Generates DHCP ACK packet.
1084 */
1085 private class TestDhcpAckPacketContext extends PacketContextAdapter {
1086 private InboundPacket inPacket;
1087
1088 public TestDhcpAckPacketContext(ConnectPoint clientCp, MacAddress clientMac,
1089 VlanId clientVlan, Ip4Address clientGwAddr,
1090 boolean withNonOnosRelayInfo) {
1091 super(0, null, null, false);
1092
1093 byte[] dhcpMsgType = new byte[1];
1094 dhcpMsgType[0] = (byte) DHCP.MsgType.DHCPACK.getValue();
1095
1096 DhcpOption dhcpOption = new DhcpOption();
1097 dhcpOption.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue());
1098 dhcpOption.setData(dhcpMsgType);
1099 dhcpOption.setLength((byte) 1);
1100
1101 DhcpOption endOption = new DhcpOption();
1102 endOption.setCode(DHCP.DHCPOptionCode.OptionCode_END.getValue());
1103
1104 DHCP dhcp = new DHCP();
1105 if (withNonOnosRelayInfo) {
1106 DhcpRelayAgentOption relayOption = new DhcpRelayAgentOption();
1107 DhcpOption circuitIdOption = new DhcpOption();
Yi Tseng440e2b72017-08-24 14:47:34 -07001108 String circuitId = NON_ONOS_CID;
1109 byte[] cid = circuitId.getBytes(Charsets.US_ASCII);
Yi Tseng7a38f9a2017-06-09 14:36:40 -07001110 circuitIdOption.setCode(DhcpRelayAgentOption.RelayAgentInfoOptions.CIRCUIT_ID.getValue());
1111 circuitIdOption.setLength((byte) cid.length);
1112 circuitIdOption.setData(cid);
1113 relayOption.setCode(DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue());
1114 relayOption.addSubOption(circuitIdOption);
1115 dhcp.setOptions(ImmutableList.of(dhcpOption, relayOption, endOption));
1116 dhcp.setGatewayIPAddress(OUTER_RELAY_IP.getIp4Address().toInt());
1117 } else {
1118 CircuitId cid = new CircuitId(clientCp.toString(), clientVlan);
1119 byte[] circuitId = cid.serialize();
1120 DhcpOption circuitIdSubOption = new DhcpOption();
1121 circuitIdSubOption.setCode(DhcpRelayAgentOption.RelayAgentInfoOptions.CIRCUIT_ID.getValue());
1122 circuitIdSubOption.setData(circuitId);
1123 circuitIdSubOption.setLength((byte) circuitId.length);
1124
1125 DhcpRelayAgentOption relayInfoOption = new DhcpRelayAgentOption();
1126 relayInfoOption.setCode(DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue());
1127 relayInfoOption.addSubOption(circuitIdSubOption);
1128 dhcp.setOptions(ImmutableList.of(dhcpOption, relayInfoOption, endOption));
1129 dhcp.setGatewayIPAddress(clientGwAddr.toInt());
1130 }
1131 dhcp.setHardwareType(DHCP.HWTYPE_ETHERNET);
1132 dhcp.setHardwareAddressLength((byte) 6);
1133 dhcp.setClientHardwareAddress(clientMac.toBytes());
1134 dhcp.setYourIPAddress(IP_FOR_CLIENT.toInt());
1135
1136 UDP udp = new UDP();
1137 udp.setPayload(dhcp);
1138 udp.setSourcePort(UDP.DHCP_SERVER_PORT);
1139 udp.setDestinationPort(UDP.DHCP_CLIENT_PORT);
1140 IPv4 ipv4 = new IPv4();
1141 ipv4.setPayload(udp);
1142 ipv4.setDestinationAddress(IP_FOR_CLIENT.toString());
1143 ipv4.setSourceAddress(SERVER_IP.toString());
1144 Ethernet eth = new Ethernet();
1145 if (withNonOnosRelayInfo) {
1146 eth.setEtherType(Ethernet.TYPE_IPV4)
1147 .setVlanID(SERVER_VLAN.toShort())
1148 .setSourceMACAddress(SERVER_MAC)
1149 .setDestinationMACAddress(OUTER_RELAY_MAC)
1150 .setPayload(ipv4);
1151 } else {
1152 eth.setEtherType(Ethernet.TYPE_IPV4)
1153 .setVlanID(SERVER_VLAN.toShort())
1154 .setSourceMACAddress(SERVER_MAC)
1155 .setDestinationMACAddress(CLIENT_MAC)
1156 .setPayload(ipv4);
1157 }
1158
1159 this.inPacket = new DefaultInboundPacket(SERVER_CONNECT_POINT, eth,
1160 ByteBuffer.wrap(eth.serialize()));
1161
1162 }
1163
1164 @Override
1165 public InboundPacket inPacket() {
1166 return this.inPacket;
1167 }
1168 }
1169
1170 private class TestArpRequestPacketContext extends PacketContextAdapter {
1171 private InboundPacket inPacket;
1172
1173 public TestArpRequestPacketContext(Interface fromInterface) {
1174 super(0, null, null, false);
1175 ARP arp = new ARP();
1176 arp.setOpCode(ARP.OP_REQUEST);
1177
1178 IpAddress targetIp = fromInterface.ipAddressesList().get(0).ipAddress();
1179 arp.setTargetProtocolAddress(targetIp.toOctets());
1180 arp.setTargetHardwareAddress(MacAddress.BROADCAST.toBytes());
1181 arp.setSenderHardwareAddress(MacAddress.NONE.toBytes());
1182 arp.setSenderProtocolAddress(Ip4Address.valueOf(0).toOctets());
1183 arp.setHardwareAddressLength((byte) MacAddress.MAC_ADDRESS_LENGTH);
1184 Ethernet eth = new Ethernet();
1185 eth.setEtherType(Ethernet.TYPE_ARP);
1186 eth.setSourceMACAddress(MacAddress.NONE);
1187 eth.setDestinationMACAddress(MacAddress.BROADCAST);
1188 eth.setVlanID(fromInterface.vlan().toShort());
1189 eth.setPayload(arp);
1190
1191 this.inPacket = new DefaultInboundPacket(fromInterface.connectPoint(), eth,
1192 ByteBuffer.wrap(eth.serialize()));
1193 }
1194
1195 @Override
1196 public InboundPacket inPacket() {
1197 return this.inPacket;
1198 }
1199 }
Kalhee Kim45fede42017-09-05 19:05:06 +00001200
1201 /**
1202 * Generates DHCP6 REQUEST packet.
1203 */
1204 private void buildDhcp6Packet(DHCP6 dhcp6, byte msgType, Ip6Address ip6Addr, IpPrefix prefix) {
1205
1206 // build address option
1207 Dhcp6IaAddressOption iaAddressOption = new Dhcp6IaAddressOption();
1208 iaAddressOption.setCode(DHCP6.OptionCode.IAADDR.value());
1209 iaAddressOption.setIp6Address(ip6Addr);
1210 iaAddressOption.setPreferredLifetime(3600);
1211 iaAddressOption.setValidLifetime(1200);
1212 iaAddressOption.setLength((short) Dhcp6IaAddressOption.DEFAULT_LEN);
1213
1214 Dhcp6IaNaOption iaNaOption = new Dhcp6IaNaOption();
1215 iaNaOption.setCode(DHCP6.OptionCode.IA_NA.value());
1216 iaNaOption.setIaId(0);
1217 iaNaOption.setT1(302400);
1218 iaNaOption.setT2(483840);
1219 List<Dhcp6Option> iaNaSubOptions = new ArrayList<Dhcp6Option>();
1220 iaNaSubOptions.add(iaAddressOption);
1221 iaNaOption.setOptions(iaNaSubOptions);
1222 iaNaOption.setLength((short) (Dhcp6IaNaOption.DEFAULT_LEN + iaAddressOption.getLength()));
1223
1224 // build prefix option
1225 Dhcp6IaPrefixOption iaPrefixOption = new Dhcp6IaPrefixOption();
1226 iaPrefixOption.setCode(DHCP6.OptionCode.IAPREFIX.value());
1227 iaPrefixOption.setIp6Prefix(prefix.address().getIp6Address());
1228 iaPrefixOption.setPrefixLength((byte) prefix.prefixLength());
1229 iaPrefixOption.setPreferredLifetime(3601);
1230 iaPrefixOption.setValidLifetime(1201);
1231 iaPrefixOption.setLength((short) Dhcp6IaPrefixOption.DEFAULT_LEN);
1232
1233 Dhcp6IaPdOption iaPdOption = new Dhcp6IaPdOption();
1234 iaPdOption.setCode(DHCP6.OptionCode.IA_PD.value());
1235 iaPdOption.setIaId(0);
1236 iaPdOption.setT1(302401);
1237 iaPdOption.setT2(483841);
1238 List<Dhcp6Option> iaPdSubOptions = new ArrayList<Dhcp6Option>();
1239 iaPdSubOptions.add(iaPrefixOption);
1240 iaPdOption.setOptions(iaPdSubOptions);
1241 iaPdOption.setLength((short) (Dhcp6IaPdOption.DEFAULT_LEN + iaPrefixOption.getLength()));
1242
1243 dhcp6.setMsgType(msgType);
1244 List<Dhcp6Option> dhcp6Options = new ArrayList<Dhcp6Option>();
1245 dhcp6Options.add(iaNaOption);
1246 dhcp6Options.add(iaPdOption);
1247 dhcp6.setOptions(dhcp6Options);
1248
1249 }
1250
1251 private void buildRelayMsg(DHCP6 dhcp6Relay, byte msgType, Ip6Address linkAddr,
1252 Ip6Address peerAddr, byte hop, byte[] interfaceIdBytes,
1253 DHCP6 dhcp6Payload) {
1254
1255 dhcp6Relay.setMsgType(msgType);
1256
1257 dhcp6Relay.setLinkAddress(linkAddr.toOctets());
1258 dhcp6Relay.setPeerAddress(peerAddr.toOctets());
1259 dhcp6Relay.setHopCount(hop);
1260 List<Dhcp6Option> options = new ArrayList<Dhcp6Option>();
1261
1262 // interfaceId option
1263 Dhcp6Option interfaceId = new Dhcp6Option();
1264 interfaceId.setCode(DHCP6.OptionCode.INTERFACE_ID.value());
1265
1266
1267 interfaceId.setData(interfaceIdBytes);
1268 interfaceId.setLength((short) interfaceIdBytes.length);
1269 Dhcp6InterfaceIdOption interfaceIdOption = new Dhcp6InterfaceIdOption(interfaceId);
Kalhee Kima0b8f652017-10-18 22:00:30 +00001270 byte[] optionData = interfaceIdOption.getData();
Kalhee Kim45fede42017-09-05 19:05:06 +00001271 ByteBuffer bb = ByteBuffer.wrap(interfaceIdBytes);
1272
1273 byte[] macAddr = new byte[MacAddress.MAC_ADDRESS_LENGTH];
Kalhee Kima0b8f652017-10-18 22:00:30 +00001274 byte[] port = new byte[optionData.length - MacAddress.MAC_ADDRESS_LENGTH -
1275 VLAN_LEN - SEPARATOR_LEN * 2];
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001276 short vlan;
Kalhee Kim45fede42017-09-05 19:05:06 +00001277 bb.get(macAddr);
1278 bb.get(); // separator
1279 bb.get(port);
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001280 bb.get(); // separator
1281 vlan = bb.getShort();
Kalhee Kim45fede42017-09-05 19:05:06 +00001282 interfaceIdOption.setMacAddress(MacAddress.valueOf(macAddr));
1283 interfaceIdOption.setInPort(port);
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001284 interfaceIdOption.setVlanId(vlan);
Kalhee Kim45fede42017-09-05 19:05:06 +00001285
1286 options.add(interfaceIdOption);
1287
1288 // relay message option
1289 Dhcp6Option relayMsgOption = new Dhcp6Option();
1290 relayMsgOption.setCode(DHCP6.OptionCode.RELAY_MSG.value());
1291 byte[] dhcp6PayloadByte = dhcp6Payload.serialize();
1292 relayMsgOption.setLength((short) dhcp6PayloadByte.length);
1293 relayMsgOption.setPayload(dhcp6Payload);
1294 Dhcp6RelayOption relayOpt = new Dhcp6RelayOption(relayMsgOption);
1295
1296 options.add(relayOpt);
1297
1298 dhcp6Relay.setOptions(options);
1299 }
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001300 private byte[] buildInterfaceId(MacAddress clientMac, short vlanId, ConnectPoint clientCp) {
1301 String inPortString = "-" + clientCp.toString() + ":";
Kalhee Kim45fede42017-09-05 19:05:06 +00001302 byte[] clientSoureMacBytes = clientMac.toBytes();
1303 byte[] inPortStringBytes = inPortString.getBytes();
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001304 byte[] vlanIdBytes = new byte[2];
1305 vlanIdBytes[0] = (byte) ((vlanId >> 8) & 0xff); // high-order byte first
1306 vlanIdBytes[1] = (byte) (vlanId & 0xff);
1307 byte[] interfaceIdBytes = new byte[clientSoureMacBytes.length + inPortStringBytes.length + vlanIdBytes.length];
Kalhee Kim45fede42017-09-05 19:05:06 +00001308
1309 System.arraycopy(clientSoureMacBytes, 0, interfaceIdBytes, 0, clientSoureMacBytes.length);
1310 System.arraycopy(inPortStringBytes, 0, interfaceIdBytes, clientSoureMacBytes.length, inPortStringBytes.length);
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001311 System.arraycopy(vlanIdBytes, 0, interfaceIdBytes, clientSoureMacBytes.length + inPortStringBytes.length,
1312 vlanIdBytes.length);
Kalhee Kim45fede42017-09-05 19:05:06 +00001313
1314 return interfaceIdBytes;
1315 }
1316
Yi Tseng525ff402017-10-23 19:39:39 -07001317 private static List<TrafficSelector> buildClientDhcpSelectors() {
1318 return Streams.concat(Dhcp4HandlerImpl.DHCP_SELECTORS.stream(),
1319 Dhcp6HandlerImpl.DHCP_SELECTORS.stream())
1320 .collect(Collectors.toList());
1321 }
1322
Kalhee Kim45fede42017-09-05 19:05:06 +00001323 private class TestDhcp6RequestPacketContext extends PacketContextAdapter {
1324
1325
1326 private InboundPacket inPacket;
1327
1328
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001329 public TestDhcp6RequestPacketContext(byte msgType, MacAddress clientMac, VlanId vlanId,
Kalhee Kim45fede42017-09-05 19:05:06 +00001330 ConnectPoint clientCp,
1331 Ip6Address clientGwAddr,
1332 int relayLevel) {
1333 super(0, null, null, false);
1334
1335 DHCP6 dhcp6 = new DHCP6();
1336 if (relayLevel > 0) {
1337 DHCP6 dhcp6Payload = new DHCP6();
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001338 buildDhcp6Packet(dhcp6Payload, msgType,
Kalhee Kim45fede42017-09-05 19:05:06 +00001339 IP_FOR_CLIENT_V6,
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001340 msgType == DHCP6.MsgType.REQUEST.value() ? PREFIX_FOR_ZERO : PREFIX_FOR_CLIENT_V6);
Kalhee Kim45fede42017-09-05 19:05:06 +00001341 DHCP6 dhcp6Parent = null;
1342 DHCP6 dhcp6Child = dhcp6Payload;
1343 for (int i = 0; i < relayLevel; i++) {
1344 dhcp6Parent = new DHCP6();
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001345 byte[] interfaceId = buildInterfaceId(clientMac, vlanId.toShort(), clientCp);
Kalhee Kim45fede42017-09-05 19:05:06 +00001346 buildRelayMsg(dhcp6Parent, DHCP6.MsgType.RELAY_FORW.value(),
1347 INTERFACE_IP_V6.ipAddress().getIp6Address(),
1348 OUTER_RELAY_IP_V6,
1349 (byte) (relayLevel - 1), interfaceId,
1350 dhcp6Child);
1351 dhcp6Child = dhcp6Parent;
1352 }
1353 if (dhcp6Parent != null) {
1354 dhcp6 = dhcp6Parent;
1355 }
1356 } else {
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001357 buildDhcp6Packet(dhcp6, msgType,
Kalhee Kim45fede42017-09-05 19:05:06 +00001358 IP_FOR_CLIENT_V6,
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001359 msgType == DHCP6.MsgType.REQUEST.value() ? PREFIX_FOR_ZERO : PREFIX_FOR_CLIENT_V6);
Kalhee Kim45fede42017-09-05 19:05:06 +00001360 }
1361
1362 UDP udp = new UDP();
1363 udp.setPayload(dhcp6);
1364 if (relayLevel > 0) {
1365 udp.setSourcePort(UDP.DHCP_V6_SERVER_PORT);
1366 } else {
1367 udp.setSourcePort(UDP.DHCP_V6_CLIENT_PORT);
1368 }
1369 udp.setDestinationPort(UDP.DHCP_V6_SERVER_PORT);
1370
1371 IPv6 ipv6 = new IPv6();
1372 ipv6.setPayload(udp);
1373 ipv6.setNextHeader(IPv6.PROTOCOL_UDP);
1374 ipv6.setDestinationAddress(SERVER_IP_V6_MCAST.toOctets());
1375 ipv6.setSourceAddress(clientGwAddr.toOctets());
1376
1377 Ethernet eth = new Ethernet();
1378 if (relayLevel > 0) {
1379 eth.setEtherType(Ethernet.TYPE_IPV6)
1380 .setVlanID(vlanId.toShort())
1381 .setSourceMACAddress(OUTER_RELAY_MAC)
1382 .setDestinationMACAddress(MacAddress.valueOf("33:33:00:01:00:02"))
1383 .setPayload(ipv6);
1384 } else {
1385 eth.setEtherType(Ethernet.TYPE_IPV6)
1386 .setVlanID(vlanId.toShort())
1387 .setSourceMACAddress(clientMac)
1388 .setDestinationMACAddress(MacAddress.valueOf("33:33:00:01:00:02"))
1389 .setPayload(ipv6);
1390 }
1391 this.inPacket = new DefaultInboundPacket(clientCp, eth,
1392 ByteBuffer.wrap(eth.serialize()));
1393 }
1394
1395 @Override
1396 public InboundPacket inPacket() {
1397 return this.inPacket;
1398 }
1399 }
1400
1401 /**
1402 * Generates DHCP6 REPLY packet.
1403 */
1404
1405 private class TestDhcp6ReplyPacketContext extends PacketContextAdapter {
1406 private InboundPacket inPacket;
1407
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001408 public TestDhcp6ReplyPacketContext(byte msgType, ConnectPoint clientCp, MacAddress clientMac,
Kalhee Kim45fede42017-09-05 19:05:06 +00001409 VlanId clientVlan, Ip6Address clientGwAddr,
1410 int relayLevel) {
1411 super(0, null, null, false);
1412
1413
1414 DHCP6 dhcp6Payload = new DHCP6();
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001415 buildDhcp6Packet(dhcp6Payload, msgType,
Kalhee Kim45fede42017-09-05 19:05:06 +00001416 IP_FOR_CLIENT_V6,
1417 PREFIX_FOR_CLIENT_V6);
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001418 byte[] interfaceId = buildInterfaceId(clientMac, clientVlan.toShort(), clientCp);
Kalhee Kim45fede42017-09-05 19:05:06 +00001419 DHCP6 dhcp6 = new DHCP6();
1420 buildRelayMsg(dhcp6, DHCP6.MsgType.RELAY_REPL.value(),
Yi Tsengaa417a62017-09-08 17:22:51 -07001421 INTERFACE_IP_V6.ipAddress().getIp6Address(),
1422 CLIENT_LL_IP_V6,
1423 (byte) 0, interfaceId,
1424 dhcp6Payload);
Kalhee Kim45fede42017-09-05 19:05:06 +00001425
1426 DHCP6 dhcp6Parent = null;
1427 DHCP6 dhcp6Child = dhcp6;
1428 for (int i = 0; i < relayLevel; i++) { // relayLevel 0 : no relay
1429 dhcp6Parent = new DHCP6();
1430
1431 buildRelayMsg(dhcp6Parent, DHCP6.MsgType.RELAY_REPL.value(),
1432 INTERFACE_IP_V6.ipAddress().getIp6Address(),
1433 OUTER_RELAY_IP_V6,
1434 (byte) relayLevel, interfaceId,
1435 dhcp6Child);
1436
1437 dhcp6Child = dhcp6Parent;
1438 }
1439 if (dhcp6Parent != null) {
1440 dhcp6 = dhcp6Parent;
1441 }
1442
1443
1444 UDP udp = new UDP();
1445 udp.setPayload(dhcp6);
1446 udp.setSourcePort(UDP.DHCP_V6_SERVER_PORT);
1447 udp.setDestinationPort(UDP.DHCP_V6_CLIENT_PORT);
1448 IPv6 ipv6 = new IPv6();
1449 ipv6.setPayload(udp);
1450 ipv6.setNextHeader(IPv6.PROTOCOL_UDP);
1451 ipv6.setDestinationAddress(IP_FOR_CLIENT_V6.toOctets());
1452 ipv6.setSourceAddress(SERVER_IP_V6.toOctets());
1453 Ethernet eth = new Ethernet();
1454 if (relayLevel > 0) {
1455 eth.setEtherType(Ethernet.TYPE_IPV6)
1456 .setVlanID(SERVER_VLAN.toShort())
1457 .setSourceMACAddress(SERVER_MAC)
1458 .setDestinationMACAddress(OUTER_RELAY_MAC)
1459 .setPayload(ipv6);
1460 } else {
1461 eth.setEtherType(Ethernet.TYPE_IPV6)
1462 .setVlanID(SERVER_VLAN.toShort())
1463 .setSourceMACAddress(SERVER_MAC)
1464 .setDestinationMACAddress(CLIENT_MAC)
1465 .setPayload(ipv6);
1466 }
1467
1468 this.inPacket = new DefaultInboundPacket(SERVER_CONNECT_POINT, eth,
1469 ByteBuffer.wrap(eth.serialize()));
1470
1471 }
1472
1473 @Override
1474 public InboundPacket inPacket() {
1475 return this.inPacket;
1476 }
1477 }
1478
Yi Tseng7a38f9a2017-06-09 14:36:40 -07001479}