blob: 883bf2fe5c41af20e380697ddb079998a231323a [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 Tseng5479fb82017-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 Tseng5479fb82017-09-01 17:24:57 -070025import com.google.common.io.Resources;
Yi Tseng2cf59912017-08-24 14:47:34 -070026import org.apache.commons.io.Charsets;
Yi Tseng5479fb82017-09-01 17:24:57 -070027import org.easymock.Capture;
28import org.easymock.CaptureType;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070029import org.easymock.EasyMock;
30import org.junit.After;
31import org.junit.Before;
32import org.junit.Test;
33import org.onlab.packet.ARP;
34import org.onlab.packet.DHCP;
Yi Tseng4fa05832017-08-17 13:08:31 -070035import org.onlab.packet.DeserializationException;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070036import org.onlab.packet.Ethernet;
37import org.onlab.packet.IPv4;
38import org.onlab.packet.Ip4Address;
Kalhee Kim1b5094f2017-09-05 19:05:06 +000039import org.onlab.packet.Ip6Address;
40import org.onlab.packet.IpPrefix;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070041import org.onlab.packet.IpAddress;
42import org.onlab.packet.MacAddress;
43import org.onlab.packet.UDP;
44import org.onlab.packet.VlanId;
45import org.onlab.packet.dhcp.CircuitId;
46import org.onlab.packet.dhcp.DhcpOption;
47import org.onlab.packet.dhcp.DhcpRelayAgentOption;
Kalhee Kim1b5094f2017-09-05 19:05:06 +000048import org.onlab.packet.dhcp.Dhcp6InterfaceIdOption;
49import org.onlab.packet.dhcp.Dhcp6RelayOption;
50import org.onlab.packet.dhcp.Dhcp6IaNaOption;
51import org.onlab.packet.dhcp.Dhcp6IaPdOption;
52import org.onlab.packet.dhcp.Dhcp6IaAddressOption;
53import org.onlab.packet.dhcp.Dhcp6IaPrefixOption;
54import org.onlab.packet.dhcp.Dhcp6Option;
55import org.onosproject.net.ConnectPoint;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070056import org.onosproject.TestApplicationId;
57import org.onosproject.cfg.ComponentConfigService;
58import org.onosproject.core.ApplicationId;
59import org.onosproject.core.CoreService;
Yi Tsenge72fbb52017-08-02 15:03:31 -070060import org.onosproject.dhcprelay.config.DefaultDhcpRelayConfig;
61import org.onosproject.dhcprelay.config.DhcpServerConfig;
Yi Tseng5479fb82017-09-01 17:24:57 -070062import org.onosproject.dhcprelay.config.IgnoreDhcpConfig;
Yi Tsenge72fbb52017-08-02 15:03:31 -070063import org.onosproject.dhcprelay.config.IndirectDhcpRelayConfig;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070064import org.onosproject.dhcprelay.store.DhcpRecord;
65import org.onosproject.dhcprelay.store.DhcpRelayStore;
66import org.onosproject.dhcprelay.store.DhcpRelayStoreEvent;
Yi Tseng76365d82017-09-12 15:55:17 -070067import org.onosproject.net.Device;
Yi Tseng5479fb82017-09-01 17:24:57 -070068import org.onosproject.net.DeviceId;
Yi Tseng76365d82017-09-12 15:55:17 -070069import org.onosproject.net.behaviour.Pipeliner;
70import org.onosproject.net.device.DeviceEvent;
71import org.onosproject.net.device.DeviceService;
Yi Tseng5479fb82017-09-01 17:24:57 -070072import org.onosproject.net.flow.DefaultTrafficSelector;
73import org.onosproject.net.flow.DefaultTrafficTreatment;
74import org.onosproject.net.flow.TrafficSelector;
75import org.onosproject.net.flow.TrafficTreatment;
76import org.onosproject.net.flowobjective.FlowObjectiveService;
77import org.onosproject.net.flowobjective.ForwardingObjective;
78import org.onosproject.net.flowobjective.Objective;
Yi Tseng4b013202017-09-08 17:22:51 -070079import org.onosproject.net.host.HostProviderService;
Ray Milkeyfacf2862017-08-03 11:58:29 -070080import org.onosproject.net.intf.Interface;
81import org.onosproject.net.intf.InterfaceServiceAdapter;
Yi Tseng5479fb82017-09-01 17:24:57 -070082import org.onosproject.net.packet.PacketPriority;
Ray Milkey69ec8712017-08-08 13:00:43 -070083import org.onosproject.routeservice.Route;
84import org.onosproject.routeservice.RouteStoreAdapter;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070085import org.onosproject.net.DefaultHost;
86import org.onosproject.net.Host;
87import org.onosproject.net.HostId;
88import org.onosproject.net.HostLocation;
89import org.onosproject.net.config.NetworkConfigRegistry;
90import org.onosproject.net.host.HostDescription;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070091import org.onosproject.net.host.HostService;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070092import org.onosproject.net.host.InterfaceIpAddress;
93import org.onosproject.net.packet.DefaultInboundPacket;
94import org.onosproject.net.packet.InboundPacket;
95import org.onosproject.net.packet.OutboundPacket;
96import org.onosproject.net.packet.PacketContext;
97import org.onosproject.net.packet.PacketContextAdapter;
98import org.onosproject.net.packet.PacketProcessor;
99import org.onosproject.net.packet.PacketServiceAdapter;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700100import org.onosproject.store.StoreDelegate;
101import org.osgi.service.component.ComponentContext;
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000102import org.onlab.packet.DHCP6;
103import org.onlab.packet.IPv6;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700104
Yi Tseng76365d82017-09-12 15:55:17 -0700105import java.io.IOException;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700106import java.nio.ByteBuffer;
107import java.util.Collection;
108import java.util.Dictionary;
109import java.util.List;
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000110import java.util.ArrayList;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700111import java.util.Map;
112import java.util.Optional;
113import java.util.Set;
114import java.util.stream.Collectors;
115
116import static org.easymock.EasyMock.*;
117import static org.junit.Assert.*;
Yi Tseng5479fb82017-09-01 17:24:57 -0700118import static org.onosproject.dhcprelay.DhcpRelayManager.DHCP_RELAY_APP;
Yi Tseng76365d82017-09-12 15:55:17 -0700119import static org.onosproject.dhcprelay.DhcpRelayManager.DHCP_SELECTORS;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700120
121public class DhcpRelayManagerTest {
Yi Tseng5479fb82017-09-01 17:24:57 -0700122 private static final String CONFIG_FILE_PATH = "dhcp-relay.json";
123 private static final DeviceId DEV_1_ID = DeviceId.deviceId("of:0000000000000001");
124 private static final DeviceId DEV_2_ID = DeviceId.deviceId("of:0000000000000002");
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700125 // Ip address for interfaces
126 private static final InterfaceIpAddress INTERFACE_IP = InterfaceIpAddress.valueOf("10.0.3.254/32");
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000127 private static final InterfaceIpAddress INTERFACE_IP_V6 = InterfaceIpAddress.valueOf("2001:db8:1::254/128");
128 private static final List<InterfaceIpAddress> INTERFACE_IPS = ImmutableList.of(INTERFACE_IP, INTERFACE_IP_V6);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700129
130 // DHCP client (will send without option 82)
131 private static final Ip4Address IP_FOR_CLIENT = Ip4Address.valueOf("10.0.0.1");
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000132 private static final Ip6Address IP_FOR_CLIENT_V6 = Ip6Address.valueOf("2001:db8:1::110");
133 private static final IpPrefix PREFIX_FOR_CLIENT_V6 = IpPrefix.valueOf("2001:db8:10::/56");
134 private static final IpPrefix PREFIX_FOR_ZERO = IpPrefix.valueOf("::/0");
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700135 private static final MacAddress CLIENT_MAC = MacAddress.valueOf("00:00:00:00:00:01");
136 private static final VlanId CLIENT_VLAN = VlanId.vlanId("100");
137 private static final ConnectPoint CLIENT_CP = ConnectPoint.deviceConnectPoint("of:0000000000000001/1");
138 private static final MacAddress CLIENT_IFACE_MAC = MacAddress.valueOf("00:00:00:00:11:01");
Yi Tseng4b013202017-09-08 17:22:51 -0700139 private static final HostLocation CLIENT_LOCATION = new HostLocation(CLIENT_CP, 0);
140 private static final HostId CLIENT_HOST_ID = HostId.hostId(CLIENT_MAC, CLIENT_VLAN);
141 private static final Ip6Address CLIENT_LL_IP_V6 = Ip6Address.valueOf("fe80::200:00ff:fe00:0001");
Charles Chan75edab72017-09-12 17:09:32 -0700142 private static final Host EXISTS_HOST = new DefaultHost(Dhcp4HandlerImpl.PROVIDER_ID,
Yi Tseng4b013202017-09-08 17:22:51 -0700143 CLIENT_HOST_ID, CLIENT_MAC, CLIENT_VLAN,
144 CLIENT_LOCATION, ImmutableSet.of(CLIENT_LL_IP_V6));
Yi Tseng58e74312017-09-30 11:35:42 +0800145 private static final Interface CLIENT_INTERFACE = createInterface("C1",
146 CLIENT_CP,
147 INTERFACE_IPS,
148 CLIENT_IFACE_MAC,
149 CLIENT_VLAN,
150 null);
151
152
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700153
Yi Tseng4b013202017-09-08 17:22:51 -0700154 // Dual homing test
155 private static final ConnectPoint CLIENT_DH_CP = ConnectPoint.deviceConnectPoint("of:0000000000000001/3");
156 private static final HostLocation CLIENT_DH_LOCATION = new HostLocation(CLIENT_DH_CP, 0);
Yi Tseng58e74312017-09-30 11:35:42 +0800157 private static final Interface CLIENT_DH_INTERFACE = createInterface("C1-DH",
158 CLIENT_DH_CP,
159 INTERFACE_IPS,
160 CLIENT_IFACE_MAC,
161 CLIENT_VLAN,
162 null);
Yi Tseng4b013202017-09-08 17:22:51 -0700163
164
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700165 // DHCP client 2 (will send with option 82, so the vlan should equals to vlan from server)
166 private static final MacAddress CLIENT2_MAC = MacAddress.valueOf("00:00:00:00:00:01");
167 private static final VlanId CLIENT2_VLAN = VlanId.NONE;
Yi Tseng58e74312017-09-30 11:35:42 +0800168 private static final VlanId CLIENT2_VLAN_NATIVE = VlanId.vlanId("20");
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700169 private static final ConnectPoint CLIENT2_CP = ConnectPoint.deviceConnectPoint("of:0000000000000001/2");
170 private static final MacAddress CLIENT2_IFACE_MAC = MacAddress.valueOf("00:00:00:00:11:01");
Yi Tseng58e74312017-09-30 11:35:42 +0800171 private static final Interface CLIENT2_INTERFACE = createInterface("C2",
172 CLIENT2_CP,
173 INTERFACE_IPS,
174 CLIENT2_IFACE_MAC,
175 CLIENT2_VLAN,
176 CLIENT2_VLAN_NATIVE);
Kalhee Kimaa5172a2017-09-15 17:43:27 +0000177 private static final VlanId CLIENT_BOGUS_VLAN = VlanId.vlanId("108");
178
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700179
180 // Outer relay information
181 private static final Ip4Address OUTER_RELAY_IP = Ip4Address.valueOf("10.0.5.253");
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000182 private static final Ip6Address OUTER_RELAY_IP_V6 = Ip6Address.valueOf("2001:db8:1::4");
183 private static final Set<IpAddress> OUTER_RELAY_IPS = ImmutableSet.of(OUTER_RELAY_IP, OUTER_RELAY_IP_V6);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700184 private static final MacAddress OUTER_RELAY_MAC = MacAddress.valueOf("00:01:02:03:04:05");
185 private static final VlanId OUTER_RELAY_VLAN = VlanId.NONE;
186 private static final ConnectPoint OUTER_RELAY_CP = ConnectPoint.deviceConnectPoint("of:0000000000000001/2");
187 private static final HostLocation OUTER_REPLAY_HL = new HostLocation(OUTER_RELAY_CP, 0);
188 private static final HostId OUTER_RELAY_HOST_ID = HostId.hostId(OUTER_RELAY_MAC, OUTER_RELAY_VLAN);
Charles Chan75edab72017-09-12 17:09:32 -0700189 private static final Host OUTER_RELAY_HOST = new DefaultHost(Dhcp4HandlerImpl.PROVIDER_ID,
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700190 OUTER_RELAY_HOST_ID,
191 OUTER_RELAY_MAC,
192 OUTER_RELAY_VLAN,
193 OUTER_REPLAY_HL,
194 OUTER_RELAY_IPS);
195
196 // DHCP Server
197 private static final MacAddress SERVER_MAC = MacAddress.valueOf("00:00:00:00:00:01");
198 private static final VlanId SERVER_VLAN = VlanId.NONE;
Yi Tseng58e74312017-09-30 11:35:42 +0800199 private static final VlanId SERVER_VLAN_NATIVE = VlanId.vlanId("10");
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700200 private static final ConnectPoint SERVER_CONNECT_POINT =
201 ConnectPoint.deviceConnectPoint("of:0000000000000001/5");
202 private static final HostLocation SERVER_LOCATION =
203 new HostLocation(SERVER_CONNECT_POINT, 0);
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000204 private static final Ip4Address GATEWAY_IP = Ip4Address.valueOf("10.0.5.253");
205 private static final Ip6Address GATEWAY_IP_V6 = Ip6Address.valueOf("2000::105:253");
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700206 private static final Ip4Address SERVER_IP = Ip4Address.valueOf("10.0.3.253");
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000207 private static final Ip6Address SERVER_IP_V6 = Ip6Address.valueOf("2000::103:253");
208 private static final Ip6Address SERVER_IP_V6_MCAST = Ip6Address.valueOf("ff02::1:2");
209 private static final Set<IpAddress> DHCP_SERVER_IPS = ImmutableSet.of(SERVER_IP, SERVER_IP_V6);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700210 private static final HostId SERVER_HOST_ID = HostId.hostId(SERVER_MAC, SERVER_VLAN);
Charles Chan75edab72017-09-12 17:09:32 -0700211 private static final Host SERVER_HOST = new DefaultHost(Dhcp4HandlerImpl.PROVIDER_ID,
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700212 SERVER_HOST_ID,
213 SERVER_MAC,
214 SERVER_VLAN,
215 SERVER_LOCATION,
216 DHCP_SERVER_IPS);
217 private static final MacAddress SERVER_IFACE_MAC = MacAddress.valueOf("00:00:00:00:00:01");
Yi Tseng58e74312017-09-30 11:35:42 +0800218 private static final Interface SERVER_INTERFACE = createInterface("SERVER",
219 SERVER_CONNECT_POINT,
220 INTERFACE_IPS,
221 SERVER_IFACE_MAC,
222 SERVER_VLAN,
223 SERVER_VLAN_NATIVE);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700224
Yi Tseng4fa05832017-08-17 13:08:31 -0700225 // Relay agent config
226 private static final Ip4Address RELAY_AGENT_IP = Ip4Address.valueOf("10.0.4.254");
227
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700228 // Components
229 private static final ApplicationId APP_ID = TestApplicationId.create(DhcpRelayManager.DHCP_RELAY_APP);
Yi Tsenge72fbb52017-08-02 15:03:31 -0700230 private static final DefaultDhcpRelayConfig CONFIG = new MockDefaultDhcpRelayConfig();
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000231 private static final IndirectDhcpRelayConfig CONFIG_INDIRECT = new MockIndirectDhcpRelayConfig();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700232 private static final Set<Interface> INTERFACES = ImmutableSet.of(
233 CLIENT_INTERFACE,
234 CLIENT2_INTERFACE,
Yi Tseng4b013202017-09-08 17:22:51 -0700235 SERVER_INTERFACE,
236 CLIENT_DH_INTERFACE
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700237 );
Yi Tseng2cf59912017-08-24 14:47:34 -0700238 private static final String NON_ONOS_CID = "Non-ONOS circuit ID";
Yi Tseng5479fb82017-09-01 17:24:57 -0700239 private static final VlanId IGNORED_VLAN = VlanId.vlanId("100");
240 private static final int IGNORE_CONTROL_PRIORITY = PacketPriority.CONTROL.priorityValue() + 1000;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700241
242 private DhcpRelayManager manager;
243 private MockPacketService packetService;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700244 private MockRouteStore mockRouteStore;
245 private MockDhcpRelayStore mockDhcpRelayStore;
Yi Tseng4b013202017-09-08 17:22:51 -0700246 private HostProviderService mockHostProviderService;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700247
Yi Tseng58e74312017-09-30 11:35:42 +0800248 private static Interface createInterface(String name, ConnectPoint connectPoint,
249 List<InterfaceIpAddress> interfaceIps,
250 MacAddress macAddress,
251 VlanId vlanId,
252 VlanId vlanNative) {
253
254 if (vlanId.equals(VlanId.NONE)) {
255 return new Interface(name, connectPoint, interfaceIps, macAddress, vlanId,
256 null, null, vlanNative);
257 } else {
258 return new Interface(name, connectPoint, interfaceIps, macAddress, vlanId,
259 null, ImmutableSet.of(vlanId), null);
260 }
261 }
262
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700263 @Before
264 public void setup() {
265 manager = new DhcpRelayManager();
266 manager.cfgService = createNiceMock(NetworkConfigRegistry.class);
267
Yi Tsenge72fbb52017-08-02 15:03:31 -0700268 expect(manager.cfgService.getConfig(APP_ID, DefaultDhcpRelayConfig.class))
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700269 .andReturn(CONFIG)
270 .anyTimes();
271
Yi Tsenge72fbb52017-08-02 15:03:31 -0700272 expect(manager.cfgService.getConfig(APP_ID, IndirectDhcpRelayConfig.class))
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000273 .andReturn(CONFIG_INDIRECT)
Yi Tsenge72fbb52017-08-02 15:03:31 -0700274 .anyTimes();
275
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700276 manager.coreService = createNiceMock(CoreService.class);
277 expect(manager.coreService.registerApplication(anyString()))
278 .andReturn(APP_ID).anyTimes();
279
280 manager.hostService = createNiceMock(HostService.class);
Yi Tseng4fa05832017-08-17 13:08:31 -0700281 expect(manager.hostService.getHostsByIp(anyObject())).andReturn(ImmutableSet.of(SERVER_HOST)).anyTimes();
282 expect(manager.hostService.getHost(OUTER_RELAY_HOST_ID)).andReturn(OUTER_RELAY_HOST).anyTimes();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700283
284 packetService = new MockPacketService();
285 manager.packetService = packetService;
286 manager.compCfgService = createNiceMock(ComponentConfigService.class);
Yi Tseng76365d82017-09-12 15:55:17 -0700287 manager.deviceService = createNiceMock(DeviceService.class);
288
289 Device device = createNiceMock(Device.class);
290 expect(device.is(Pipeliner.class)).andReturn(true).anyTimes();
291
292 expect(manager.deviceService.getDevice(DEV_1_ID)).andReturn(device).anyTimes();
293 expect(manager.deviceService.getDevice(DEV_2_ID)).andReturn(device).anyTimes();
294 replay(manager.deviceService, device);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700295
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700296 mockRouteStore = new MockRouteStore();
297 mockDhcpRelayStore = new MockDhcpRelayStore();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700298 manager.dhcpRelayStore = mockDhcpRelayStore;
299
300 manager.interfaceService = new MockInterfaceService();
Yi Tseng5479fb82017-09-01 17:24:57 -0700301 manager.flowObjectiveService = EasyMock.niceMock(FlowObjectiveService.class);
Yi Tseng4b013202017-09-08 17:22:51 -0700302 mockHostProviderService = createNiceMock(HostProviderService.class);
Yi Tseng51301292017-07-28 13:02:59 -0700303 Dhcp4HandlerImpl v4Handler = new Dhcp4HandlerImpl();
Yi Tseng4b013202017-09-08 17:22:51 -0700304 v4Handler.providerService = mockHostProviderService;
Yi Tseng51301292017-07-28 13:02:59 -0700305 v4Handler.dhcpRelayStore = mockDhcpRelayStore;
306 v4Handler.hostService = manager.hostService;
Yi Tseng51301292017-07-28 13:02:59 -0700307 v4Handler.interfaceService = manager.interfaceService;
308 v4Handler.packetService = manager.packetService;
309 v4Handler.routeStore = mockRouteStore;
310 manager.v4Handler = v4Handler;
311
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000312 Dhcp6HandlerImpl v6Handler = new Dhcp6HandlerImpl();
313 v6Handler.dhcpRelayStore = mockDhcpRelayStore;
314 v6Handler.hostService = manager.hostService;
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000315 v6Handler.interfaceService = manager.interfaceService;
316 v6Handler.packetService = manager.packetService;
317 v6Handler.routeStore = mockRouteStore;
Yi Tseng4b013202017-09-08 17:22:51 -0700318 v6Handler.providerService = mockHostProviderService;
Yi Tsenge72fbb52017-08-02 15:03:31 -0700319 manager.v6Handler = v6Handler;
320
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700321 // properties
322 Dictionary<String, Object> dictionary = createNiceMock(Dictionary.class);
323 expect(dictionary.get("arpEnabled")).andReturn(true).anyTimes();
324 ComponentContext context = createNiceMock(ComponentContext.class);
325 expect(context.getProperties()).andReturn(dictionary).anyTimes();
326
Yi Tseng58e74312017-09-30 11:35:42 +0800327 replay(manager.cfgService, manager.coreService, manager.hostService,
328 manager.compCfgService, dictionary, context);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700329 manager.activate(context);
330 }
331
332 @After
333 public void tearDown() {
334 manager.deactivate();
335 }
336
337 /**
338 * Relay a DHCP packet without option 82.
339 * Should add new host to host store after dhcp ack.
340 */
341 @Test
342 public void relayDhcpWithoutAgentInfo() {
Yi Tseng4b013202017-09-08 17:22:51 -0700343 replay(mockHostProviderService);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700344 // send request
345 packetService.processPacket(new TestDhcpRequestPacketContext(CLIENT_MAC,
346 CLIENT_VLAN,
347 CLIENT_CP,
348 INTERFACE_IP.ipAddress().getIp4Address(),
349 false));
Yi Tseng4b013202017-09-08 17:22:51 -0700350 // won't trigger the host provider service
351 verify(mockHostProviderService);
352 reset(mockHostProviderService);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700353
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700354 assertEquals(0, mockRouteStore.routes.size());
355
Yi Tseng4b013202017-09-08 17:22:51 -0700356 HostId expectHostId = HostId.hostId(CLIENT_MAC, CLIENT_VLAN);
357 Capture<HostDescription> capturedHostDesc = newCapture();
358 mockHostProviderService.hostDetected(eq(expectHostId), capture(capturedHostDesc), eq(false));
359 replay(mockHostProviderService);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700360 // send ack
361 packetService.processPacket(new TestDhcpAckPacketContext(CLIENT_CP, CLIENT_MAC,
362 CLIENT_VLAN, INTERFACE_IP.ipAddress().getIp4Address(),
363 false));
Yi Tseng4b013202017-09-08 17:22:51 -0700364 verify(mockHostProviderService);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700365 assertEquals(0, mockRouteStore.routes.size());
366
Yi Tseng4b013202017-09-08 17:22:51 -0700367 HostDescription host = capturedHostDesc.getValue();
368 assertEquals(false, host.configured());
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700369 assertEquals(CLIENT_CP.deviceId(), host.location().elementId());
370 assertEquals(CLIENT_CP.port(), host.location().port());
Yi Tseng4b013202017-09-08 17:22:51 -0700371 assertEquals(1, host.ipAddress().size());
372 assertEquals(IP_FOR_CLIENT, host.ipAddress().iterator().next());
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700373 }
374
375 /**
376 * Relay a DHCP packet with option 82 (Indirectly connected host).
377 */
378 @Test
379 public void relayDhcpWithAgentInfo() {
Yi Tseng4b013202017-09-08 17:22:51 -0700380 replay(mockHostProviderService);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700381 // Assume outer dhcp relay agent exists in store already
382 // send request
383 packetService.processPacket(new TestDhcpRequestPacketContext(CLIENT2_MAC,
384 CLIENT2_VLAN,
385 CLIENT2_CP,
386 INTERFACE_IP.ipAddress().getIp4Address(),
387 true));
Yi Tseng4b013202017-09-08 17:22:51 -0700388 // No routes
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700389 assertEquals(0, mockRouteStore.routes.size());
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700390 // send ack
391 packetService.processPacket(new TestDhcpAckPacketContext(CLIENT2_CP,
392 CLIENT2_MAC,
393 CLIENT2_VLAN,
394 INTERFACE_IP.ipAddress().getIp4Address(),
395 true));
396
Yi Tseng4b013202017-09-08 17:22:51 -0700397 // won't trigger the host provider service
398 verify(mockHostProviderService);
399 reset(mockHostProviderService);
400
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700401 assertEquals(1, mockRouteStore.routes.size());
402
403 Route route = mockRouteStore.routes.get(0);
404 assertEquals(OUTER_RELAY_IP, route.nextHop());
405 assertEquals(IP_FOR_CLIENT.toIpPrefix(), route.prefix());
406 assertEquals(Route.Source.STATIC, route.source());
407 }
408
409 @Test
Yi Tseng4fa05832017-08-17 13:08:31 -0700410 public void testWithRelayAgentConfig() throws DeserializationException {
411 manager.v4Handler
412 .setDefaultDhcpServerConfigs(ImmutableList.of(new MockDhcpServerConfig(RELAY_AGENT_IP)));
Yi Tseng4ec727d2017-08-31 11:21:00 -0700413 manager.v4Handler
414 .setIndirectDhcpServerConfigs(ImmutableList.of(new MockDhcpServerConfig(RELAY_AGENT_IP)));
Yi Tseng4fa05832017-08-17 13:08:31 -0700415 packetService.processPacket(new TestDhcpRequestPacketContext(CLIENT2_MAC,
416 CLIENT2_VLAN,
417 CLIENT2_CP,
418 INTERFACE_IP.ipAddress().getIp4Address(),
419 true));
420 OutboundPacket outPacket = packetService.emittedPacket;
421 byte[] outData = outPacket.data().array();
422 Ethernet eth = Ethernet.deserializer().deserialize(outData, 0, outData.length);
423 IPv4 ip = (IPv4) eth.getPayload();
424 UDP udp = (UDP) ip.getPayload();
425 DHCP dhcp = (DHCP) udp.getPayload();
426 assertEquals(RELAY_AGENT_IP.toInt(), dhcp.getGatewayIPAddress());
427 }
428
429 @Test
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700430 public void testArpRequest() throws Exception {
431 packetService.processPacket(new TestArpRequestPacketContext(CLIENT_INTERFACE));
Ray Milkeybd52a052017-08-23 15:23:50 -0700432 OutboundPacket outboundPacket = packetService.emittedPacket;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700433 byte[] outPacketData = outboundPacket.data().array();
434 Ethernet eth = Ethernet.deserializer().deserialize(outPacketData, 0, outPacketData.length);
435
436 assertEquals(eth.getEtherType(), Ethernet.TYPE_ARP);
437 ARP arp = (ARP) eth.getPayload();
438 assertArrayEquals(arp.getSenderHardwareAddress(), CLIENT_INTERFACE.mac().toBytes());
439 }
440
Yi Tseng5479fb82017-09-01 17:24:57 -0700441 /**
442 * Ignores specific vlans from specific devices if config.
443 *
444 * @throws Exception the exception from this test
445 */
446 @Test
447 public void testIgnoreVlan() throws Exception {
448 ObjectMapper om = new ObjectMapper();
449 JsonNode json = om.readTree(Resources.getResource(CONFIG_FILE_PATH));
450 IgnoreDhcpConfig config = new IgnoreDhcpConfig();
451 json = json.path("apps").path(DHCP_RELAY_APP).path(IgnoreDhcpConfig.KEY);
452 config.init(APP_ID, IgnoreDhcpConfig.KEY, json, om, null);
453
454 Capture<Objective> capturedFromDev1 = newCapture(CaptureType.ALL);
455 manager.flowObjectiveService.apply(eq(DEV_1_ID), capture(capturedFromDev1));
Yi Tseng76365d82017-09-12 15:55:17 -0700456 expectLastCall().times(DHCP_SELECTORS.size());
Yi Tseng5479fb82017-09-01 17:24:57 -0700457 Capture<Objective> capturedFromDev2 = newCapture(CaptureType.ALL);
458 manager.flowObjectiveService.apply(eq(DEV_2_ID), capture(capturedFromDev2));
Yi Tseng76365d82017-09-12 15:55:17 -0700459 expectLastCall().times(DHCP_SELECTORS.size());
Yi Tseng5479fb82017-09-01 17:24:57 -0700460 replay(manager.flowObjectiveService);
461 manager.updateConfig(config);
462 verify(manager.flowObjectiveService);
463
464 List<Objective> objectivesFromDev1 = capturedFromDev1.getValues();
465 List<Objective> objectivesFromDev2 = capturedFromDev2.getValues();
466
467 assertTrue(objectivesFromDev1.containsAll(objectivesFromDev2));
468 assertTrue(objectivesFromDev2.containsAll(objectivesFromDev1));
469 TrafficTreatment dropTreatment = DefaultTrafficTreatment.emptyTreatment();
470 dropTreatment.clearedDeferred();
471
472 for (int index = 0; index < objectivesFromDev1.size(); index++) {
473 TrafficSelector selector =
474 DefaultTrafficSelector.builder(DhcpRelayManager.DHCP_SELECTORS.get(index))
475 .matchVlanId(IGNORED_VLAN)
476 .build();
477 ForwardingObjective fwd = (ForwardingObjective) objectivesFromDev1.get(index);
478 assertEquals(selector, fwd.selector());
479 assertEquals(dropTreatment, fwd.treatment());
480 assertEquals(IGNORE_CONTROL_PRIORITY, fwd.priority());
481 assertEquals(ForwardingObjective.Flag.VERSATILE, fwd.flag());
482 assertEquals(Objective.Operation.ADD, fwd.op());
Yi Tseng76365d82017-09-12 15:55:17 -0700483 fwd.context().ifPresent(ctx -> {
484 ctx.onSuccess(fwd);
485 });
Yi Tseng5479fb82017-09-01 17:24:57 -0700486 }
Yi Tseng76365d82017-09-12 15:55:17 -0700487 objectivesFromDev2.forEach(obj -> obj.context().ifPresent(ctx -> ctx.onSuccess(obj)));
Yi Tseng5479fb82017-09-01 17:24:57 -0700488 assertEquals(2, manager.ignoredVlans.size());
489 }
490
491 /**
492 * "IgnoreVlan" policy should be removed when the config removed.
493 */
494 @Test
495 public void testRemoveIgnoreVlan() {
496 manager.ignoredVlans.put(DEV_1_ID, IGNORED_VLAN);
497 manager.ignoredVlans.put(DEV_2_ID, IGNORED_VLAN);
498 IgnoreDhcpConfig config = new IgnoreDhcpConfig();
499
500 Capture<Objective> capturedFromDev1 = newCapture(CaptureType.ALL);
501 manager.flowObjectiveService.apply(eq(DEV_1_ID), capture(capturedFromDev1));
Yi Tseng76365d82017-09-12 15:55:17 -0700502 expectLastCall().times(DHCP_SELECTORS.size());
Yi Tseng5479fb82017-09-01 17:24:57 -0700503 Capture<Objective> capturedFromDev2 = newCapture(CaptureType.ALL);
504 manager.flowObjectiveService.apply(eq(DEV_2_ID), capture(capturedFromDev2));
Yi Tseng76365d82017-09-12 15:55:17 -0700505 expectLastCall().times(DHCP_SELECTORS.size());
Yi Tseng5479fb82017-09-01 17:24:57 -0700506 replay(manager.flowObjectiveService);
507 manager.removeConfig(config);
508 verify(manager.flowObjectiveService);
509
510 List<Objective> objectivesFromDev1 = capturedFromDev1.getValues();
511 List<Objective> objectivesFromDev2 = capturedFromDev2.getValues();
512
513 assertTrue(objectivesFromDev1.containsAll(objectivesFromDev2));
514 assertTrue(objectivesFromDev2.containsAll(objectivesFromDev1));
515 TrafficTreatment dropTreatment = DefaultTrafficTreatment.emptyTreatment();
516 dropTreatment.clearedDeferred();
517
518 for (int index = 0; index < objectivesFromDev1.size(); index++) {
519 TrafficSelector selector =
520 DefaultTrafficSelector.builder(DhcpRelayManager.DHCP_SELECTORS.get(index))
521 .matchVlanId(IGNORED_VLAN)
522 .build();
523 ForwardingObjective fwd = (ForwardingObjective) objectivesFromDev1.get(index);
524 assertEquals(selector, fwd.selector());
525 assertEquals(dropTreatment, fwd.treatment());
526 assertEquals(IGNORE_CONTROL_PRIORITY, fwd.priority());
527 assertEquals(ForwardingObjective.Flag.VERSATILE, fwd.flag());
528 assertEquals(Objective.Operation.REMOVE, fwd.op());
Yi Tseng76365d82017-09-12 15:55:17 -0700529 fwd.context().ifPresent(ctx -> {
530 ctx.onSuccess(fwd);
531 });
Yi Tseng5479fb82017-09-01 17:24:57 -0700532 }
Yi Tseng76365d82017-09-12 15:55:17 -0700533 objectivesFromDev2.forEach(obj -> obj.context().ifPresent(ctx -> ctx.onSuccess(obj)));
Yi Tseng5479fb82017-09-01 17:24:57 -0700534 assertEquals(0, manager.ignoredVlans.size());
535 }
536
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000537 /**
Yi Tseng76365d82017-09-12 15:55:17 -0700538 * Should ignore ignore rules installation when device not available.
539 */
540 @Test
541 public void testIgnoreUnknownDevice() throws IOException {
542 reset(manager.deviceService);
543 Device device = createNiceMock(Device.class);
544 expect(device.is(Pipeliner.class)).andReturn(true).anyTimes();
545
546 expect(manager.deviceService.getDevice(DEV_1_ID)).andReturn(device).anyTimes();
547 expect(manager.deviceService.getDevice(DEV_2_ID)).andReturn(null).anyTimes();
548
549 ObjectMapper om = new ObjectMapper();
550 JsonNode json = om.readTree(Resources.getResource(CONFIG_FILE_PATH));
551 IgnoreDhcpConfig config = new IgnoreDhcpConfig();
552 json = json.path("apps").path(DHCP_RELAY_APP).path(IgnoreDhcpConfig.KEY);
553 config.init(APP_ID, IgnoreDhcpConfig.KEY, json, om, null);
554
555 Capture<Objective> capturedFromDev1 = newCapture(CaptureType.ALL);
556 manager.flowObjectiveService.apply(eq(DEV_1_ID), capture(capturedFromDev1));
557 expectLastCall().times(DHCP_SELECTORS.size());
558 replay(manager.flowObjectiveService, manager.deviceService, device);
559
560 manager.updateConfig(config);
561 capturedFromDev1.getValues().forEach(obj -> obj.context().ifPresent(ctx -> ctx.onSuccess(obj)));
562
563 assertEquals(1, manager.ignoredVlans.size());
564 }
565
566 /**
567 * Should try install ignore rules when device comes up.
568 */
569 @Test
570 public void testInstallIgnoreRuleWhenDeviceComesUp() throws IOException {
571 ObjectMapper om = new ObjectMapper();
572 JsonNode json = om.readTree(Resources.getResource(CONFIG_FILE_PATH));
573 IgnoreDhcpConfig config = new IgnoreDhcpConfig();
574 json = json.path("apps").path(DHCP_RELAY_APP).path(IgnoreDhcpConfig.KEY);
575 config.init(APP_ID, IgnoreDhcpConfig.KEY, json, om, null);
576
577 reset(manager.cfgService, manager.flowObjectiveService, manager.deviceService);
578 expect(manager.cfgService.getConfig(APP_ID, IgnoreDhcpConfig.class))
579 .andReturn(config).anyTimes();
580
581 Device device = createNiceMock(Device.class);
582 expect(device.is(Pipeliner.class)).andReturn(true).anyTimes();
583 expect(device.id()).andReturn(DEV_1_ID).anyTimes();
584 expect(manager.deviceService.getDevice(DEV_1_ID)).andReturn(device).anyTimes();
585 DeviceEvent event = new DeviceEvent(DeviceEvent.Type.DEVICE_ADDED, device);
586 Capture<Objective> capturedFromDev1 = newCapture(CaptureType.ALL);
587 manager.flowObjectiveService.apply(eq(DEV_1_ID), capture(capturedFromDev1));
588 expectLastCall().times(DHCP_SELECTORS.size());
589 replay(manager.cfgService, manager.flowObjectiveService, manager.deviceService, device);
590 assertEquals(0, manager.ignoredVlans.size());
591 manager.deviceListener.event(event);
592 capturedFromDev1.getValues().forEach(obj -> obj.context().ifPresent(ctx -> ctx.onSuccess(obj)));
593 assertEquals(1, manager.ignoredVlans.size());
594 }
595
596 /**
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000597 * Relay a DHCP6 packet without relay option
598 * Note: Should add new host to host store after dhcp ack.
599 */
600 @Test
601 public void relayDhcp6WithoutAgentInfo() {
Yi Tseng4b013202017-09-08 17:22:51 -0700602 replay(mockHostProviderService);
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000603 // send request
Kalhee Kimaa5172a2017-09-15 17:43:27 +0000604 packetService.processPacket(new TestDhcp6RequestPacketContext(DHCP6.MsgType.REQUEST.value(),
605 CLIENT_MAC,
606 CLIENT_VLAN,
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000607 CLIENT_CP,
608 INTERFACE_IP_V6.ipAddress().getIp6Address(),
609 0));
610
Yi Tseng4b013202017-09-08 17:22:51 -0700611 verify(mockHostProviderService);
612 reset(mockHostProviderService);
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000613 assertEquals(0, mockRouteStore.routes.size());
614
Yi Tseng4b013202017-09-08 17:22:51 -0700615 Capture<HostDescription> capturedHostDesc = newCapture();
616 mockHostProviderService.hostDetected(eq(HostId.hostId(CLIENT_MAC, CLIENT_VLAN)),
617 capture(capturedHostDesc), eq(false));
618 replay(mockHostProviderService);
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000619 // send reply
Kalhee Kimaa5172a2017-09-15 17:43:27 +0000620 packetService.processPacket(new TestDhcp6ReplyPacketContext(DHCP6.MsgType.REPLY.value(),
621 CLIENT_CP, CLIENT_MAC,
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000622 CLIENT_VLAN,
623 INTERFACE_IP_V6.ipAddress().getIp6Address(),
624 0));
Yi Tseng4b013202017-09-08 17:22:51 -0700625 verify(mockHostProviderService);
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000626 assertEquals(0, mockRouteStore.routes.size());
627
Yi Tseng4b013202017-09-08 17:22:51 -0700628 HostDescription host = capturedHostDesc.getValue();
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000629 assertEquals(CLIENT_VLAN, host.vlan());
630 assertEquals(CLIENT_CP.deviceId(), host.location().elementId());
631 assertEquals(CLIENT_CP.port(), host.location().port());
Yi Tseng4b013202017-09-08 17:22:51 -0700632 assertEquals(1, host.ipAddress().size());
633 assertEquals(IP_FOR_CLIENT_V6, host.ipAddress().iterator().next());
Kalhee Kimaa5172a2017-09-15 17:43:27 +0000634
635 // send release
636 packetService.processPacket(new TestDhcp6RequestPacketContext(DHCP6.MsgType.RELEASE.value(),
637 CLIENT_MAC,
638 CLIENT_VLAN,
639 CLIENT_CP,
640 INTERFACE_IP_V6.ipAddress().getIp6Address(),
641 0));
642
643 assertEquals(null, manager.hostService.getHost(HostId.hostId(CLIENT_MAC, CLIENT_VLAN)));
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000644 }
645
646 /**
647 * Relay a DHCP6 packet with Relay Message opion (Indirectly connected host).
648 */
649 @Test
650 public void relayDhcp6WithAgentInfo() {
Yi Tseng4b013202017-09-08 17:22:51 -0700651 replay(mockHostProviderService);
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000652 // Assume outer dhcp6 relay agent exists in store already
653 // send request
Kalhee Kimaa5172a2017-09-15 17:43:27 +0000654 packetService.processPacket(new TestDhcp6RequestPacketContext(DHCP6.MsgType.REQUEST.value(),
655 CLIENT2_MAC,
656 CLIENT2_VLAN,
657 CLIENT2_CP,
658 OUTER_RELAY_IP_V6,
659 1));
660
661 assertEquals(0, mockRouteStore.routes.size());
662
663 // send reply
664 packetService.processPacket(new TestDhcp6ReplyPacketContext(DHCP6.MsgType.REPLY.value(), CLIENT2_CP,
665 CLIENT2_MAC,
666 CLIENT2_VLAN,
667 OUTER_RELAY_IP_V6,
668 1));
669
670 // won't trigger the host provider service
671 verify(mockHostProviderService);
672 reset(mockHostProviderService);
673 assertEquals(2, mockRouteStore.routes.size()); // ipAddress and prefix
674
675 Route aRoute = mockRouteStore.routes.stream()
676 .filter(rt -> rt.prefix().contains(IP_FOR_CLIENT_V6))
677 .findFirst()
678 .orElse(null);
679 assertNotEquals(null, aRoute);
680
681 aRoute = mockRouteStore.routes.stream()
682 .filter(rt -> rt.prefix().contains(PREFIX_FOR_CLIENT_V6))
683 .findFirst()
684 .orElse(null);
685 assertNotEquals(null, aRoute);
686
687 // send release msg
688 packetService.processPacket(new TestDhcp6RequestPacketContext(DHCP6.MsgType.RELEASE.value(),
689 CLIENT2_MAC,
690 CLIENT2_VLAN,
691 CLIENT2_CP,
692 OUTER_RELAY_IP_V6,
693 1));
694
695 aRoute = mockRouteStore.routes.stream()
696 .filter(rt -> rt.prefix().contains(IP_FOR_CLIENT_V6))
697 .findFirst()
698 .orElse(null);
699 assertEquals(null, aRoute);
700
701 aRoute = mockRouteStore.routes.stream()
702 .filter(rt -> rt.prefix().contains(PREFIX_FOR_CLIENT_V6))
703 .findFirst()
704 .orElse(null);
705 assertEquals(null, aRoute);
706
707 assertEquals(0, mockRouteStore.routes.size());
708
709 }
710
711 /**
712 * Relay a DHCP6 packet with Relay Message opion (Indirectly connected host) and server responded
713 * with vlan differnt from client interface vlan.
714 */
715 @Test
716 public void relayDhcp6WithAgentInfoWrongVlan() {
717 replay(mockHostProviderService);
718 // Assume outer dhcp6 relay agent exists in store already
719 // send request
720 packetService.processPacket(new TestDhcp6RequestPacketContext(DHCP6.MsgType.REQUEST.value(),
721 CLIENT2_MAC,
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000722 CLIENT2_VLAN,
723 CLIENT2_CP,
724 INTERFACE_IP_V6.ipAddress().getIp6Address(),
725 1));
726
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000727 assertEquals(0, mockRouteStore.routes.size());
728
729 // send reply
Kalhee Kimaa5172a2017-09-15 17:43:27 +0000730 packetService.processPacket(new TestDhcp6ReplyPacketContext(DHCP6.MsgType.REPLY.value(),
731 CLIENT2_CP,
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000732 CLIENT2_MAC,
Kalhee Kimaa5172a2017-09-15 17:43:27 +0000733 CLIENT_BOGUS_VLAN, // mismatch
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000734 INTERFACE_IP_V6.ipAddress().getIp6Address(),
735 1));
736
Yi Tseng4b013202017-09-08 17:22:51 -0700737 // won't trigger the host provider service
738 verify(mockHostProviderService);
739 reset(mockHostProviderService);
Kalhee Kimaa5172a2017-09-15 17:43:27 +0000740 assertEquals(0, mockRouteStore.routes.size()); // ipAddress and prefix
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000741
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000742 }
Yi Tseng4b013202017-09-08 17:22:51 -0700743
Kalhee Kimaa5172a2017-09-15 17:43:27 +0000744
Yi Tseng4b013202017-09-08 17:22:51 -0700745 @Test
746 public void testDhcp4DualHome() {
747 PacketContext packetContext =
748 new TestDhcpAckPacketContext(CLIENT_DH_CP, CLIENT_MAC, CLIENT_VLAN,
749 INTERFACE_IP.ipAddress().getIp4Address(),
750 false);
751 reset(manager.hostService);
752 expect(manager.hostService.getHost(CLIENT_HOST_ID)).andReturn(EXISTS_HOST).anyTimes();
753 Capture<HostDescription> capturedHostDesc = newCapture();
754 mockHostProviderService.hostDetected(eq(CLIENT_HOST_ID), capture(capturedHostDesc), eq(false));
755 replay(mockHostProviderService, manager.hostService);
756 packetService.processPacket(packetContext);
757 verify(mockHostProviderService);
758
759 HostDescription hostDesc = capturedHostDesc.getValue();
760 Set<HostLocation> hostLocations = hostDesc.locations();
761 assertEquals(2, hostLocations.size());
762 assertTrue(hostLocations.contains(CLIENT_LOCATION));
763 assertTrue(hostLocations.contains(CLIENT_DH_LOCATION));
764 }
765
766 @Test
767 public void testDhcp6DualHome() {
768 PacketContext packetContext =
Kalhee Kimaa5172a2017-09-15 17:43:27 +0000769 new TestDhcp6ReplyPacketContext(DHCP6.MsgType.REPLY.value(),
770 CLIENT_DH_CP, CLIENT_MAC, CLIENT_VLAN,
Yi Tseng4b013202017-09-08 17:22:51 -0700771 INTERFACE_IP_V6.ipAddress().getIp6Address(),
772 0);
773 reset(manager.hostService);
774 expect(manager.hostService.getHostsByIp(CLIENT_LL_IP_V6)).andReturn(ImmutableSet.of(EXISTS_HOST)).anyTimes();
775
776 // FIXME: currently DHCPv6 has a bug, we can't get correct vlan of client......
777 // XXX: The vlan relied from DHCP6 handler might be wrong, do hack here
778 HostId hostId = HostId.hostId(CLIENT_MAC, VlanId.NONE);
779 expect(manager.hostService.getHost(hostId)).andReturn(EXISTS_HOST).anyTimes();
780
781 // XXX: sometimes this will work, sometimes not
782 expect(manager.hostService.getHost(CLIENT_HOST_ID)).andReturn(EXISTS_HOST).anyTimes();
783
784 Capture<HostDescription> capturedHostDesc = newCapture();
785
786 // XXX: also a hack here
787 mockHostProviderService.hostDetected(eq(hostId), capture(capturedHostDesc), eq(false));
788 expectLastCall().anyTimes();
789
790 mockHostProviderService.hostDetected(eq(CLIENT_HOST_ID), capture(capturedHostDesc), eq(false));
791 expectLastCall().anyTimes();
792 replay(mockHostProviderService, manager.hostService);
793 packetService.processPacket(packetContext);
794 verify(mockHostProviderService);
795
796 HostDescription hostDesc = capturedHostDesc.getValue();
797 Set<HostLocation> hostLocations = hostDesc.locations();
798 assertEquals(2, hostLocations.size());
799 assertTrue(hostLocations.contains(CLIENT_LOCATION));
800 assertTrue(hostLocations.contains(CLIENT_DH_LOCATION));
801 }
802
Yi Tsenge72fbb52017-08-02 15:03:31 -0700803 private static class MockDefaultDhcpRelayConfig extends DefaultDhcpRelayConfig {
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700804 @Override
805 public boolean isValid() {
806 return true;
807 }
808
809 @Override
Yi Tsenge72fbb52017-08-02 15:03:31 -0700810 public List<DhcpServerConfig> dhcpServerConfigs() {
Yi Tseng4fa05832017-08-17 13:08:31 -0700811 return ImmutableList.of(new MockDhcpServerConfig(null));
Yi Tsenge72fbb52017-08-02 15:03:31 -0700812 }
813 }
814
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000815 private static class MockIndirectDhcpRelayConfig extends IndirectDhcpRelayConfig {
816 @Override
817 public boolean isValid() {
818 return true;
819 }
820
821 @Override
822 public List<DhcpServerConfig> dhcpServerConfigs() {
823 return ImmutableList.of(new MockDhcpServerConfig(null));
824 }
825 }
826
Yi Tsenge72fbb52017-08-02 15:03:31 -0700827 private static class MockDhcpServerConfig extends DhcpServerConfig {
Yi Tseng4fa05832017-08-17 13:08:31 -0700828 Ip4Address relayAgentIp;
829
830 /**
831 * Create mocked version DHCP server config.
832 *
833 * @param relayAgentIp the relay agent Ip config; null if we don't need it
834 */
835 public MockDhcpServerConfig(Ip4Address relayAgentIp) {
836 this.relayAgentIp = relayAgentIp;
837 }
838
839 @Override
840 public Optional<Ip4Address> getRelayAgentIp4() {
841 return Optional.ofNullable(relayAgentIp);
842 }
843
Yi Tsenge72fbb52017-08-02 15:03:31 -0700844 @Override
845 public Optional<ConnectPoint> getDhcpServerConnectPoint() {
846 return Optional.of(SERVER_CONNECT_POINT);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700847 }
848
Yi Tsenge72fbb52017-08-02 15:03:31 -0700849 @Override
850 public Optional<Ip4Address> getDhcpServerIp4() {
851 return Optional.of(SERVER_IP);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700852 }
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000853
854 @Override
855 public Optional<Ip4Address> getDhcpGatewayIp4() {
856 return Optional.of(GATEWAY_IP);
857 }
858
859 @Override
860 public Optional<Ip6Address> getDhcpServerIp6() {
861 return Optional.of(SERVER_IP_V6);
862 }
863
864 @Override
865 public Optional<Ip6Address> getDhcpGatewayIp6() {
866 return Optional.of(GATEWAY_IP_V6);
867 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700868 }
869
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700870 private class MockRouteStore extends RouteStoreAdapter {
871 private List<Route> routes = Lists.newArrayList();
872
873 @Override
874 public void updateRoute(Route route) {
875 routes.add(route);
876 }
Kalhee Kimaa5172a2017-09-15 17:43:27 +0000877
878 @Override
879 public void removeRoute(Route route) {
880 routes.remove(route);
881 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700882 }
883
884 private class MockInterfaceService extends InterfaceServiceAdapter {
885
886 @Override
887 public Set<Interface> getInterfaces() {
888 return INTERFACES;
889 }
890
891 @Override
892 public Set<Interface> getInterfacesByIp(IpAddress ip) {
893 return INTERFACES.stream()
894 .filter(iface -> {
895 return iface.ipAddressesList().stream()
896 .anyMatch(ifaceIp -> ifaceIp.ipAddress().equals(ip));
897 })
898 .collect(Collectors.toSet());
899 }
900
901 @Override
902 public Set<Interface> getInterfacesByPort(ConnectPoint port) {
903 return INTERFACES.stream()
904 .filter(iface -> iface.connectPoint().equals(port))
905 .collect(Collectors.toSet());
906 }
907 }
908
909 private class MockDhcpRelayStore implements DhcpRelayStore {
910 StoreDelegate<DhcpRelayStoreEvent> delegate;
911 private Map<HostId, DhcpRecord> records = Maps.newHashMap();
912
913 @Override
914 public void updateDhcpRecord(HostId hostId, DhcpRecord dhcpRecord) {
915 records.put(hostId, dhcpRecord);
916 DhcpRelayStoreEvent event = new DhcpRelayStoreEvent(DhcpRelayStoreEvent.Type.UPDATED,
917 dhcpRecord);
918 if (delegate != null) {
919 delegate.notify(event);
920 }
921 }
922
923 @Override
924 public Optional<DhcpRecord> getDhcpRecord(HostId hostId) {
925 return Optional.ofNullable(records.get(hostId));
926 }
927
928 @Override
929 public Collection<DhcpRecord> getDhcpRecords() {
930 return records.values();
931 }
932
933 @Override
934 public Optional<DhcpRecord> removeDhcpRecord(HostId hostId) {
935 DhcpRecord dhcpRecord = records.remove(hostId);
936 if (dhcpRecord != null) {
937 DhcpRelayStoreEvent event = new DhcpRelayStoreEvent(DhcpRelayStoreEvent.Type.REMOVED,
938 dhcpRecord);
939 if (delegate != null) {
940 delegate.notify(event);
941 }
942 }
943 return Optional.ofNullable(dhcpRecord);
944 }
945
946 @Override
947 public void setDelegate(StoreDelegate<DhcpRelayStoreEvent> delegate) {
948 this.delegate = delegate;
949 }
950
951 @Override
952 public void unsetDelegate(StoreDelegate<DhcpRelayStoreEvent> delegate) {
953 this.delegate = null;
954 }
955
956 @Override
957 public boolean hasDelegate() {
958 return this.delegate != null;
959 }
960 }
961
962 private class MockPacketService extends PacketServiceAdapter {
963 Set<PacketProcessor> packetProcessors = Sets.newHashSet();
Ray Milkeybd52a052017-08-23 15:23:50 -0700964 OutboundPacket emittedPacket;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700965
966 @Override
967 public void addProcessor(PacketProcessor processor, int priority) {
968 packetProcessors.add(processor);
969 }
970
971 public void processPacket(PacketContext packetContext) {
972 packetProcessors.forEach(p -> p.process(packetContext));
973 }
974
975 @Override
976 public void emit(OutboundPacket packet) {
Ray Milkeybd52a052017-08-23 15:23:50 -0700977 this.emittedPacket = packet;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700978 }
979 }
980
981
982
983 /**
984 * Generates DHCP REQUEST packet.
985 */
986 private class TestDhcpRequestPacketContext extends PacketContextAdapter {
987
988
989 private InboundPacket inPacket;
990
991 public TestDhcpRequestPacketContext(MacAddress clientMac, VlanId vlanId,
992 ConnectPoint clientCp,
993 Ip4Address clientGwAddr,
994 boolean withNonOnosRelayInfo) {
995 super(0, null, null, false);
996 byte[] dhcpMsgType = new byte[1];
997 dhcpMsgType[0] = (byte) DHCP.MsgType.DHCPREQUEST.getValue();
998
999 DhcpOption dhcpOption = new DhcpOption();
1000 dhcpOption.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue());
1001 dhcpOption.setData(dhcpMsgType);
1002 dhcpOption.setLength((byte) 1);
1003 DhcpOption endOption = new DhcpOption();
1004 endOption.setCode(DHCP.DHCPOptionCode.OptionCode_END.getValue());
1005
1006 DHCP dhcp = new DHCP();
1007 dhcp.setHardwareType(DHCP.HWTYPE_ETHERNET);
1008 dhcp.setHardwareAddressLength((byte) 6);
1009 dhcp.setClientHardwareAddress(clientMac.toBytes());
1010 if (withNonOnosRelayInfo) {
1011 DhcpRelayAgentOption relayOption = new DhcpRelayAgentOption();
1012 DhcpOption circuitIdOption = new DhcpOption();
1013 CircuitId circuitId = new CircuitId("Custom option", VlanId.NONE);
1014 byte[] cid = circuitId.serialize();
1015 circuitIdOption.setCode(DhcpRelayAgentOption.RelayAgentInfoOptions.CIRCUIT_ID.getValue());
1016 circuitIdOption.setLength((byte) cid.length);
1017 circuitIdOption.setData(cid);
1018 relayOption.setCode(DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue());
1019 relayOption.addSubOption(circuitIdOption);
1020 dhcp.setOptions(ImmutableList.of(dhcpOption, relayOption, endOption));
1021 dhcp.setGatewayIPAddress(OUTER_RELAY_IP.getIp4Address().toInt());
1022 } else {
1023 dhcp.setOptions(ImmutableList.of(dhcpOption, endOption));
1024 }
1025
1026
1027 UDP udp = new UDP();
1028 udp.setPayload(dhcp);
1029 udp.setSourcePort(UDP.DHCP_CLIENT_PORT);
1030 udp.setDestinationPort(UDP.DHCP_SERVER_PORT);
1031
1032 IPv4 ipv4 = new IPv4();
1033 ipv4.setPayload(udp);
1034 ipv4.setDestinationAddress(SERVER_IP.toInt());
1035 ipv4.setSourceAddress(clientGwAddr.toInt());
1036
1037 Ethernet eth = new Ethernet();
1038 if (withNonOnosRelayInfo) {
1039 eth.setEtherType(Ethernet.TYPE_IPV4)
1040 .setVlanID(vlanId.toShort())
1041 .setSourceMACAddress(OUTER_RELAY_MAC)
1042 .setDestinationMACAddress(MacAddress.BROADCAST)
1043 .setPayload(ipv4);
1044 } else {
1045 eth.setEtherType(Ethernet.TYPE_IPV4)
1046 .setVlanID(vlanId.toShort())
1047 .setSourceMACAddress(clientMac)
1048 .setDestinationMACAddress(MacAddress.BROADCAST)
1049 .setPayload(ipv4);
1050 }
1051
1052 this.inPacket = new DefaultInboundPacket(clientCp, eth,
1053 ByteBuffer.wrap(eth.serialize()));
1054 }
1055
1056 @Override
1057 public InboundPacket inPacket() {
1058 return this.inPacket;
1059 }
1060 }
1061
1062 /**
1063 * Generates DHCP ACK packet.
1064 */
1065 private class TestDhcpAckPacketContext extends PacketContextAdapter {
1066 private InboundPacket inPacket;
1067
1068 public TestDhcpAckPacketContext(ConnectPoint clientCp, MacAddress clientMac,
1069 VlanId clientVlan, Ip4Address clientGwAddr,
1070 boolean withNonOnosRelayInfo) {
1071 super(0, null, null, false);
1072
1073 byte[] dhcpMsgType = new byte[1];
1074 dhcpMsgType[0] = (byte) DHCP.MsgType.DHCPACK.getValue();
1075
1076 DhcpOption dhcpOption = new DhcpOption();
1077 dhcpOption.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue());
1078 dhcpOption.setData(dhcpMsgType);
1079 dhcpOption.setLength((byte) 1);
1080
1081 DhcpOption endOption = new DhcpOption();
1082 endOption.setCode(DHCP.DHCPOptionCode.OptionCode_END.getValue());
1083
1084 DHCP dhcp = new DHCP();
1085 if (withNonOnosRelayInfo) {
1086 DhcpRelayAgentOption relayOption = new DhcpRelayAgentOption();
1087 DhcpOption circuitIdOption = new DhcpOption();
Yi Tseng2cf59912017-08-24 14:47:34 -07001088 String circuitId = NON_ONOS_CID;
1089 byte[] cid = circuitId.getBytes(Charsets.US_ASCII);
Yi Tseng7a38f9a2017-06-09 14:36:40 -07001090 circuitIdOption.setCode(DhcpRelayAgentOption.RelayAgentInfoOptions.CIRCUIT_ID.getValue());
1091 circuitIdOption.setLength((byte) cid.length);
1092 circuitIdOption.setData(cid);
1093 relayOption.setCode(DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue());
1094 relayOption.addSubOption(circuitIdOption);
1095 dhcp.setOptions(ImmutableList.of(dhcpOption, relayOption, endOption));
1096 dhcp.setGatewayIPAddress(OUTER_RELAY_IP.getIp4Address().toInt());
1097 } else {
1098 CircuitId cid = new CircuitId(clientCp.toString(), clientVlan);
1099 byte[] circuitId = cid.serialize();
1100 DhcpOption circuitIdSubOption = new DhcpOption();
1101 circuitIdSubOption.setCode(DhcpRelayAgentOption.RelayAgentInfoOptions.CIRCUIT_ID.getValue());
1102 circuitIdSubOption.setData(circuitId);
1103 circuitIdSubOption.setLength((byte) circuitId.length);
1104
1105 DhcpRelayAgentOption relayInfoOption = new DhcpRelayAgentOption();
1106 relayInfoOption.setCode(DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue());
1107 relayInfoOption.addSubOption(circuitIdSubOption);
1108 dhcp.setOptions(ImmutableList.of(dhcpOption, relayInfoOption, endOption));
1109 dhcp.setGatewayIPAddress(clientGwAddr.toInt());
1110 }
1111 dhcp.setHardwareType(DHCP.HWTYPE_ETHERNET);
1112 dhcp.setHardwareAddressLength((byte) 6);
1113 dhcp.setClientHardwareAddress(clientMac.toBytes());
1114 dhcp.setYourIPAddress(IP_FOR_CLIENT.toInt());
1115
1116 UDP udp = new UDP();
1117 udp.setPayload(dhcp);
1118 udp.setSourcePort(UDP.DHCP_SERVER_PORT);
1119 udp.setDestinationPort(UDP.DHCP_CLIENT_PORT);
1120 IPv4 ipv4 = new IPv4();
1121 ipv4.setPayload(udp);
1122 ipv4.setDestinationAddress(IP_FOR_CLIENT.toString());
1123 ipv4.setSourceAddress(SERVER_IP.toString());
1124 Ethernet eth = new Ethernet();
1125 if (withNonOnosRelayInfo) {
1126 eth.setEtherType(Ethernet.TYPE_IPV4)
1127 .setVlanID(SERVER_VLAN.toShort())
1128 .setSourceMACAddress(SERVER_MAC)
1129 .setDestinationMACAddress(OUTER_RELAY_MAC)
1130 .setPayload(ipv4);
1131 } else {
1132 eth.setEtherType(Ethernet.TYPE_IPV4)
1133 .setVlanID(SERVER_VLAN.toShort())
1134 .setSourceMACAddress(SERVER_MAC)
1135 .setDestinationMACAddress(CLIENT_MAC)
1136 .setPayload(ipv4);
1137 }
1138
1139 this.inPacket = new DefaultInboundPacket(SERVER_CONNECT_POINT, eth,
1140 ByteBuffer.wrap(eth.serialize()));
1141
1142 }
1143
1144 @Override
1145 public InboundPacket inPacket() {
1146 return this.inPacket;
1147 }
1148 }
1149
1150 private class TestArpRequestPacketContext extends PacketContextAdapter {
1151 private InboundPacket inPacket;
1152
1153 public TestArpRequestPacketContext(Interface fromInterface) {
1154 super(0, null, null, false);
1155 ARP arp = new ARP();
1156 arp.setOpCode(ARP.OP_REQUEST);
1157
1158 IpAddress targetIp = fromInterface.ipAddressesList().get(0).ipAddress();
1159 arp.setTargetProtocolAddress(targetIp.toOctets());
1160 arp.setTargetHardwareAddress(MacAddress.BROADCAST.toBytes());
1161 arp.setSenderHardwareAddress(MacAddress.NONE.toBytes());
1162 arp.setSenderProtocolAddress(Ip4Address.valueOf(0).toOctets());
1163 arp.setHardwareAddressLength((byte) MacAddress.MAC_ADDRESS_LENGTH);
1164 Ethernet eth = new Ethernet();
1165 eth.setEtherType(Ethernet.TYPE_ARP);
1166 eth.setSourceMACAddress(MacAddress.NONE);
1167 eth.setDestinationMACAddress(MacAddress.BROADCAST);
1168 eth.setVlanID(fromInterface.vlan().toShort());
1169 eth.setPayload(arp);
1170
1171 this.inPacket = new DefaultInboundPacket(fromInterface.connectPoint(), eth,
1172 ByteBuffer.wrap(eth.serialize()));
1173 }
1174
1175 @Override
1176 public InboundPacket inPacket() {
1177 return this.inPacket;
1178 }
1179 }
Kalhee Kim1b5094f2017-09-05 19:05:06 +00001180
1181 /**
1182 * Generates DHCP6 REQUEST packet.
1183 */
1184 private void buildDhcp6Packet(DHCP6 dhcp6, byte msgType, Ip6Address ip6Addr, IpPrefix prefix) {
1185
1186 // build address option
1187 Dhcp6IaAddressOption iaAddressOption = new Dhcp6IaAddressOption();
1188 iaAddressOption.setCode(DHCP6.OptionCode.IAADDR.value());
1189 iaAddressOption.setIp6Address(ip6Addr);
1190 iaAddressOption.setPreferredLifetime(3600);
1191 iaAddressOption.setValidLifetime(1200);
1192 iaAddressOption.setLength((short) Dhcp6IaAddressOption.DEFAULT_LEN);
1193
1194 Dhcp6IaNaOption iaNaOption = new Dhcp6IaNaOption();
1195 iaNaOption.setCode(DHCP6.OptionCode.IA_NA.value());
1196 iaNaOption.setIaId(0);
1197 iaNaOption.setT1(302400);
1198 iaNaOption.setT2(483840);
1199 List<Dhcp6Option> iaNaSubOptions = new ArrayList<Dhcp6Option>();
1200 iaNaSubOptions.add(iaAddressOption);
1201 iaNaOption.setOptions(iaNaSubOptions);
1202 iaNaOption.setLength((short) (Dhcp6IaNaOption.DEFAULT_LEN + iaAddressOption.getLength()));
1203
1204 // build prefix option
1205 Dhcp6IaPrefixOption iaPrefixOption = new Dhcp6IaPrefixOption();
1206 iaPrefixOption.setCode(DHCP6.OptionCode.IAPREFIX.value());
1207 iaPrefixOption.setIp6Prefix(prefix.address().getIp6Address());
1208 iaPrefixOption.setPrefixLength((byte) prefix.prefixLength());
1209 iaPrefixOption.setPreferredLifetime(3601);
1210 iaPrefixOption.setValidLifetime(1201);
1211 iaPrefixOption.setLength((short) Dhcp6IaPrefixOption.DEFAULT_LEN);
1212
1213 Dhcp6IaPdOption iaPdOption = new Dhcp6IaPdOption();
1214 iaPdOption.setCode(DHCP6.OptionCode.IA_PD.value());
1215 iaPdOption.setIaId(0);
1216 iaPdOption.setT1(302401);
1217 iaPdOption.setT2(483841);
1218 List<Dhcp6Option> iaPdSubOptions = new ArrayList<Dhcp6Option>();
1219 iaPdSubOptions.add(iaPrefixOption);
1220 iaPdOption.setOptions(iaPdSubOptions);
1221 iaPdOption.setLength((short) (Dhcp6IaPdOption.DEFAULT_LEN + iaPrefixOption.getLength()));
1222
1223 dhcp6.setMsgType(msgType);
1224 List<Dhcp6Option> dhcp6Options = new ArrayList<Dhcp6Option>();
1225 dhcp6Options.add(iaNaOption);
1226 dhcp6Options.add(iaPdOption);
1227 dhcp6.setOptions(dhcp6Options);
1228
1229 }
1230
1231 private void buildRelayMsg(DHCP6 dhcp6Relay, byte msgType, Ip6Address linkAddr,
1232 Ip6Address peerAddr, byte hop, byte[] interfaceIdBytes,
1233 DHCP6 dhcp6Payload) {
1234
1235 dhcp6Relay.setMsgType(msgType);
1236
1237 dhcp6Relay.setLinkAddress(linkAddr.toOctets());
1238 dhcp6Relay.setPeerAddress(peerAddr.toOctets());
1239 dhcp6Relay.setHopCount(hop);
1240 List<Dhcp6Option> options = new ArrayList<Dhcp6Option>();
1241
1242 // interfaceId option
1243 Dhcp6Option interfaceId = new Dhcp6Option();
1244 interfaceId.setCode(DHCP6.OptionCode.INTERFACE_ID.value());
1245
1246
1247 interfaceId.setData(interfaceIdBytes);
1248 interfaceId.setLength((short) interfaceIdBytes.length);
1249 Dhcp6InterfaceIdOption interfaceIdOption = new Dhcp6InterfaceIdOption(interfaceId);
1250 ByteBuffer bb = ByteBuffer.wrap(interfaceIdBytes);
1251
1252 byte[] macAddr = new byte[MacAddress.MAC_ADDRESS_LENGTH];
1253 byte[] port = new byte[21];
Kalhee Kimaa5172a2017-09-15 17:43:27 +00001254 short vlan;
Kalhee Kim1b5094f2017-09-05 19:05:06 +00001255 bb.get(macAddr);
1256 bb.get(); // separator
1257 bb.get(port);
Kalhee Kimaa5172a2017-09-15 17:43:27 +00001258 bb.get(); // separator
1259 vlan = bb.getShort();
Kalhee Kim1b5094f2017-09-05 19:05:06 +00001260 interfaceIdOption.setMacAddress(MacAddress.valueOf(macAddr));
1261 interfaceIdOption.setInPort(port);
Kalhee Kimaa5172a2017-09-15 17:43:27 +00001262 interfaceIdOption.setVlanId(vlan);
Kalhee Kim1b5094f2017-09-05 19:05:06 +00001263
1264 options.add(interfaceIdOption);
1265
1266 // relay message option
1267 Dhcp6Option relayMsgOption = new Dhcp6Option();
1268 relayMsgOption.setCode(DHCP6.OptionCode.RELAY_MSG.value());
1269 byte[] dhcp6PayloadByte = dhcp6Payload.serialize();
1270 relayMsgOption.setLength((short) dhcp6PayloadByte.length);
1271 relayMsgOption.setPayload(dhcp6Payload);
1272 Dhcp6RelayOption relayOpt = new Dhcp6RelayOption(relayMsgOption);
1273
1274 options.add(relayOpt);
1275
1276 dhcp6Relay.setOptions(options);
1277 }
Kalhee Kimaa5172a2017-09-15 17:43:27 +00001278 private byte[] buildInterfaceId(MacAddress clientMac, short vlanId, ConnectPoint clientCp) {
1279 String inPortString = "-" + clientCp.toString() + ":";
Kalhee Kim1b5094f2017-09-05 19:05:06 +00001280 byte[] clientSoureMacBytes = clientMac.toBytes();
1281 byte[] inPortStringBytes = inPortString.getBytes();
Kalhee Kimaa5172a2017-09-15 17:43:27 +00001282 byte[] vlanIdBytes = new byte[2];
1283 vlanIdBytes[0] = (byte) ((vlanId >> 8) & 0xff); // high-order byte first
1284 vlanIdBytes[1] = (byte) (vlanId & 0xff);
1285 byte[] interfaceIdBytes = new byte[clientSoureMacBytes.length + inPortStringBytes.length + vlanIdBytes.length];
Kalhee Kim1b5094f2017-09-05 19:05:06 +00001286
1287 System.arraycopy(clientSoureMacBytes, 0, interfaceIdBytes, 0, clientSoureMacBytes.length);
1288 System.arraycopy(inPortStringBytes, 0, interfaceIdBytes, clientSoureMacBytes.length, inPortStringBytes.length);
Kalhee Kimaa5172a2017-09-15 17:43:27 +00001289 System.arraycopy(vlanIdBytes, 0, interfaceIdBytes, clientSoureMacBytes.length + inPortStringBytes.length,
1290 vlanIdBytes.length);
Kalhee Kim1b5094f2017-09-05 19:05:06 +00001291
1292 return interfaceIdBytes;
1293 }
1294
1295 private class TestDhcp6RequestPacketContext extends PacketContextAdapter {
1296
1297
1298 private InboundPacket inPacket;
1299
1300
Kalhee Kimaa5172a2017-09-15 17:43:27 +00001301 public TestDhcp6RequestPacketContext(byte msgType, MacAddress clientMac, VlanId vlanId,
Kalhee Kim1b5094f2017-09-05 19:05:06 +00001302 ConnectPoint clientCp,
1303 Ip6Address clientGwAddr,
1304 int relayLevel) {
1305 super(0, null, null, false);
1306
1307 DHCP6 dhcp6 = new DHCP6();
1308 if (relayLevel > 0) {
1309 DHCP6 dhcp6Payload = new DHCP6();
Kalhee Kimaa5172a2017-09-15 17:43:27 +00001310 buildDhcp6Packet(dhcp6Payload, msgType,
Kalhee Kim1b5094f2017-09-05 19:05:06 +00001311 IP_FOR_CLIENT_V6,
Kalhee Kimaa5172a2017-09-15 17:43:27 +00001312 msgType == DHCP6.MsgType.REQUEST.value() ? PREFIX_FOR_ZERO : PREFIX_FOR_CLIENT_V6);
Kalhee Kim1b5094f2017-09-05 19:05:06 +00001313 DHCP6 dhcp6Parent = null;
1314 DHCP6 dhcp6Child = dhcp6Payload;
1315 for (int i = 0; i < relayLevel; i++) {
1316 dhcp6Parent = new DHCP6();
Kalhee Kimaa5172a2017-09-15 17:43:27 +00001317 byte[] interfaceId = buildInterfaceId(clientMac, vlanId.toShort(), clientCp);
Kalhee Kim1b5094f2017-09-05 19:05:06 +00001318 buildRelayMsg(dhcp6Parent, DHCP6.MsgType.RELAY_FORW.value(),
1319 INTERFACE_IP_V6.ipAddress().getIp6Address(),
1320 OUTER_RELAY_IP_V6,
1321 (byte) (relayLevel - 1), interfaceId,
1322 dhcp6Child);
1323 dhcp6Child = dhcp6Parent;
1324 }
1325 if (dhcp6Parent != null) {
1326 dhcp6 = dhcp6Parent;
1327 }
1328 } else {
Kalhee Kimaa5172a2017-09-15 17:43:27 +00001329 buildDhcp6Packet(dhcp6, msgType,
Kalhee Kim1b5094f2017-09-05 19:05:06 +00001330 IP_FOR_CLIENT_V6,
Kalhee Kimaa5172a2017-09-15 17:43:27 +00001331 msgType == DHCP6.MsgType.REQUEST.value() ? PREFIX_FOR_ZERO : PREFIX_FOR_CLIENT_V6);
Kalhee Kim1b5094f2017-09-05 19:05:06 +00001332 }
1333
1334 UDP udp = new UDP();
1335 udp.setPayload(dhcp6);
1336 if (relayLevel > 0) {
1337 udp.setSourcePort(UDP.DHCP_V6_SERVER_PORT);
1338 } else {
1339 udp.setSourcePort(UDP.DHCP_V6_CLIENT_PORT);
1340 }
1341 udp.setDestinationPort(UDP.DHCP_V6_SERVER_PORT);
1342
1343 IPv6 ipv6 = new IPv6();
1344 ipv6.setPayload(udp);
1345 ipv6.setNextHeader(IPv6.PROTOCOL_UDP);
1346 ipv6.setDestinationAddress(SERVER_IP_V6_MCAST.toOctets());
1347 ipv6.setSourceAddress(clientGwAddr.toOctets());
1348
1349 Ethernet eth = new Ethernet();
1350 if (relayLevel > 0) {
1351 eth.setEtherType(Ethernet.TYPE_IPV6)
1352 .setVlanID(vlanId.toShort())
1353 .setSourceMACAddress(OUTER_RELAY_MAC)
1354 .setDestinationMACAddress(MacAddress.valueOf("33:33:00:01:00:02"))
1355 .setPayload(ipv6);
1356 } else {
1357 eth.setEtherType(Ethernet.TYPE_IPV6)
1358 .setVlanID(vlanId.toShort())
1359 .setSourceMACAddress(clientMac)
1360 .setDestinationMACAddress(MacAddress.valueOf("33:33:00:01:00:02"))
1361 .setPayload(ipv6);
1362 }
1363 this.inPacket = new DefaultInboundPacket(clientCp, eth,
1364 ByteBuffer.wrap(eth.serialize()));
1365 }
1366
1367 @Override
1368 public InboundPacket inPacket() {
1369 return this.inPacket;
1370 }
1371 }
1372
1373 /**
1374 * Generates DHCP6 REPLY packet.
1375 */
1376
1377 private class TestDhcp6ReplyPacketContext extends PacketContextAdapter {
1378 private InboundPacket inPacket;
1379
Kalhee Kimaa5172a2017-09-15 17:43:27 +00001380 public TestDhcp6ReplyPacketContext(byte msgType, ConnectPoint clientCp, MacAddress clientMac,
Kalhee Kim1b5094f2017-09-05 19:05:06 +00001381 VlanId clientVlan, Ip6Address clientGwAddr,
1382 int relayLevel) {
1383 super(0, null, null, false);
1384
1385
1386 DHCP6 dhcp6Payload = new DHCP6();
Kalhee Kimaa5172a2017-09-15 17:43:27 +00001387 buildDhcp6Packet(dhcp6Payload, msgType,
Kalhee Kim1b5094f2017-09-05 19:05:06 +00001388 IP_FOR_CLIENT_V6,
1389 PREFIX_FOR_CLIENT_V6);
Kalhee Kimaa5172a2017-09-15 17:43:27 +00001390 byte[] interfaceId = buildInterfaceId(clientMac, clientVlan.toShort(), clientCp);
Kalhee Kim1b5094f2017-09-05 19:05:06 +00001391 DHCP6 dhcp6 = new DHCP6();
1392 buildRelayMsg(dhcp6, DHCP6.MsgType.RELAY_REPL.value(),
Yi Tseng4b013202017-09-08 17:22:51 -07001393 INTERFACE_IP_V6.ipAddress().getIp6Address(),
1394 CLIENT_LL_IP_V6,
1395 (byte) 0, interfaceId,
1396 dhcp6Payload);
Kalhee Kim1b5094f2017-09-05 19:05:06 +00001397
1398 DHCP6 dhcp6Parent = null;
1399 DHCP6 dhcp6Child = dhcp6;
1400 for (int i = 0; i < relayLevel; i++) { // relayLevel 0 : no relay
1401 dhcp6Parent = new DHCP6();
1402
1403 buildRelayMsg(dhcp6Parent, DHCP6.MsgType.RELAY_REPL.value(),
1404 INTERFACE_IP_V6.ipAddress().getIp6Address(),
1405 OUTER_RELAY_IP_V6,
1406 (byte) relayLevel, interfaceId,
1407 dhcp6Child);
1408
1409 dhcp6Child = dhcp6Parent;
1410 }
1411 if (dhcp6Parent != null) {
1412 dhcp6 = dhcp6Parent;
1413 }
1414
1415
1416 UDP udp = new UDP();
1417 udp.setPayload(dhcp6);
1418 udp.setSourcePort(UDP.DHCP_V6_SERVER_PORT);
1419 udp.setDestinationPort(UDP.DHCP_V6_CLIENT_PORT);
1420 IPv6 ipv6 = new IPv6();
1421 ipv6.setPayload(udp);
1422 ipv6.setNextHeader(IPv6.PROTOCOL_UDP);
1423 ipv6.setDestinationAddress(IP_FOR_CLIENT_V6.toOctets());
1424 ipv6.setSourceAddress(SERVER_IP_V6.toOctets());
1425 Ethernet eth = new Ethernet();
1426 if (relayLevel > 0) {
1427 eth.setEtherType(Ethernet.TYPE_IPV6)
1428 .setVlanID(SERVER_VLAN.toShort())
1429 .setSourceMACAddress(SERVER_MAC)
1430 .setDestinationMACAddress(OUTER_RELAY_MAC)
1431 .setPayload(ipv6);
1432 } else {
1433 eth.setEtherType(Ethernet.TYPE_IPV6)
1434 .setVlanID(SERVER_VLAN.toShort())
1435 .setSourceMACAddress(SERVER_MAC)
1436 .setDestinationMACAddress(CLIENT_MAC)
1437 .setPayload(ipv6);
1438 }
1439
1440 this.inPacket = new DefaultInboundPacket(SERVER_CONNECT_POINT, eth,
1441 ByteBuffer.wrap(eth.serialize()));
1442
1443 }
1444
1445 @Override
1446 public InboundPacket inPacket() {
1447 return this.inPacket;
1448 }
1449 }
1450
Yi Tseng7a38f9a2017-06-09 14:36:40 -07001451}