blob: 0de95f0bcb650adbc5610e554a0109bc2551d86e [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 Tseng51f1be92017-09-01 17:24:57 -070025import com.google.common.io.Resources;
Yi Tseng440e2b72017-08-24 14:47:34 -070026import org.apache.commons.io.Charsets;
Yi Tseng51f1be92017-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 Tseng3df7f9d2017-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 Kim45fede42017-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 Kim45fede42017-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 Tseng483ac6f2017-08-02 15:03:31 -070060import org.onosproject.dhcprelay.config.DefaultDhcpRelayConfig;
61import org.onosproject.dhcprelay.config.DhcpServerConfig;
Yi Tseng51f1be92017-09-01 17:24:57 -070062import org.onosproject.dhcprelay.config.IgnoreDhcpConfig;
Yi Tseng483ac6f2017-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 Tseng127ffe52017-09-12 15:55:17 -070067import org.onosproject.net.Device;
Yi Tseng51f1be92017-09-01 17:24:57 -070068import org.onosproject.net.DeviceId;
Yi Tseng127ffe52017-09-12 15:55:17 -070069import org.onosproject.net.behaviour.Pipeliner;
70import org.onosproject.net.device.DeviceEvent;
71import org.onosproject.net.device.DeviceService;
Yi Tseng51f1be92017-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 Tsengaa417a62017-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 Tseng51f1be92017-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 Kim45fede42017-09-05 19:05:06 +0000102import org.onlab.packet.DHCP6;
103import org.onlab.packet.IPv6;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700104
Yi Tseng127ffe52017-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 Kim45fede42017-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 Tseng51f1be92017-09-01 17:24:57 -0700118import static org.onosproject.dhcprelay.DhcpRelayManager.DHCP_RELAY_APP;
Yi Tseng127ffe52017-09-12 15:55:17 -0700119import static org.onosproject.dhcprelay.DhcpRelayManager.DHCP_SELECTORS;
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 Tseng7a38f9a2017-06-09 14:36:40 -0700230 // Components
231 private static final ApplicationId APP_ID = TestApplicationId.create(DhcpRelayManager.DHCP_RELAY_APP);
Yi Tseng483ac6f2017-08-02 15:03:31 -0700232 private static final DefaultDhcpRelayConfig CONFIG = new MockDefaultDhcpRelayConfig();
Kalhee Kim45fede42017-09-05 19:05:06 +0000233 private static final IndirectDhcpRelayConfig CONFIG_INDIRECT = new MockIndirectDhcpRelayConfig();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700234 private static final Set<Interface> INTERFACES = ImmutableSet.of(
235 CLIENT_INTERFACE,
236 CLIENT2_INTERFACE,
Yi Tsengaa417a62017-09-08 17:22:51 -0700237 SERVER_INTERFACE,
238 CLIENT_DH_INTERFACE
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700239 );
Yi Tseng440e2b72017-08-24 14:47:34 -0700240 private static final String NON_ONOS_CID = "Non-ONOS circuit ID";
Yi Tseng51f1be92017-09-01 17:24:57 -0700241 private static final VlanId IGNORED_VLAN = VlanId.vlanId("100");
242 private static final int IGNORE_CONTROL_PRIORITY = PacketPriority.CONTROL.priorityValue() + 1000;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700243
244 private DhcpRelayManager manager;
245 private MockPacketService packetService;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700246 private MockRouteStore mockRouteStore;
247 private MockDhcpRelayStore mockDhcpRelayStore;
Yi Tsengaa417a62017-09-08 17:22:51 -0700248 private HostProviderService mockHostProviderService;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700249
Yi Tseng4025a102017-09-30 11:35:42 +0800250 private static Interface createInterface(String name, ConnectPoint connectPoint,
251 List<InterfaceIpAddress> interfaceIps,
252 MacAddress macAddress,
253 VlanId vlanId,
254 VlanId vlanNative) {
255
256 if (vlanId.equals(VlanId.NONE)) {
257 return new Interface(name, connectPoint, interfaceIps, macAddress, vlanId,
258 null, null, vlanNative);
259 } else {
260 return new Interface(name, connectPoint, interfaceIps, macAddress, vlanId,
261 null, ImmutableSet.of(vlanId), null);
262 }
263 }
264
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700265 @Before
266 public void setup() {
267 manager = new DhcpRelayManager();
268 manager.cfgService = createNiceMock(NetworkConfigRegistry.class);
269
Yi Tseng483ac6f2017-08-02 15:03:31 -0700270 expect(manager.cfgService.getConfig(APP_ID, DefaultDhcpRelayConfig.class))
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700271 .andReturn(CONFIG)
272 .anyTimes();
273
Yi Tseng483ac6f2017-08-02 15:03:31 -0700274 expect(manager.cfgService.getConfig(APP_ID, IndirectDhcpRelayConfig.class))
Kalhee Kim45fede42017-09-05 19:05:06 +0000275 .andReturn(CONFIG_INDIRECT)
Yi Tseng483ac6f2017-08-02 15:03:31 -0700276 .anyTimes();
277
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700278 manager.coreService = createNiceMock(CoreService.class);
279 expect(manager.coreService.registerApplication(anyString()))
280 .andReturn(APP_ID).anyTimes();
281
282 manager.hostService = createNiceMock(HostService.class);
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700283 expect(manager.hostService.getHostsByIp(anyObject())).andReturn(ImmutableSet.of(SERVER_HOST)).anyTimes();
284 expect(manager.hostService.getHost(OUTER_RELAY_HOST_ID)).andReturn(OUTER_RELAY_HOST).anyTimes();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700285
286 packetService = new MockPacketService();
287 manager.packetService = packetService;
288 manager.compCfgService = createNiceMock(ComponentConfigService.class);
Yi Tseng127ffe52017-09-12 15:55:17 -0700289 manager.deviceService = createNiceMock(DeviceService.class);
290
291 Device device = createNiceMock(Device.class);
292 expect(device.is(Pipeliner.class)).andReturn(true).anyTimes();
293
294 expect(manager.deviceService.getDevice(DEV_1_ID)).andReturn(device).anyTimes();
295 expect(manager.deviceService.getDevice(DEV_2_ID)).andReturn(device).anyTimes();
296 replay(manager.deviceService, device);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700297
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700298 mockRouteStore = new MockRouteStore();
299 mockDhcpRelayStore = new MockDhcpRelayStore();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700300 manager.dhcpRelayStore = mockDhcpRelayStore;
301
302 manager.interfaceService = new MockInterfaceService();
Yi Tseng51f1be92017-09-01 17:24:57 -0700303 manager.flowObjectiveService = EasyMock.niceMock(FlowObjectiveService.class);
Yi Tsengaa417a62017-09-08 17:22:51 -0700304 mockHostProviderService = createNiceMock(HostProviderService.class);
Yi Tseng51301292017-07-28 13:02:59 -0700305 Dhcp4HandlerImpl v4Handler = new Dhcp4HandlerImpl();
Yi Tsengaa417a62017-09-08 17:22:51 -0700306 v4Handler.providerService = mockHostProviderService;
Yi Tseng51301292017-07-28 13:02:59 -0700307 v4Handler.dhcpRelayStore = mockDhcpRelayStore;
308 v4Handler.hostService = manager.hostService;
Yi Tseng51301292017-07-28 13:02:59 -0700309 v4Handler.interfaceService = manager.interfaceService;
310 v4Handler.packetService = manager.packetService;
311 v4Handler.routeStore = mockRouteStore;
312 manager.v4Handler = v4Handler;
313
Kalhee Kim45fede42017-09-05 19:05:06 +0000314 Dhcp6HandlerImpl v6Handler = new Dhcp6HandlerImpl();
315 v6Handler.dhcpRelayStore = mockDhcpRelayStore;
316 v6Handler.hostService = manager.hostService;
Kalhee Kim45fede42017-09-05 19:05:06 +0000317 v6Handler.interfaceService = manager.interfaceService;
318 v6Handler.packetService = manager.packetService;
319 v6Handler.routeStore = mockRouteStore;
Yi Tsengaa417a62017-09-08 17:22:51 -0700320 v6Handler.providerService = mockHostProviderService;
Yi Tseng483ac6f2017-08-02 15:03:31 -0700321 manager.v6Handler = v6Handler;
322
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700323 // properties
324 Dictionary<String, Object> dictionary = createNiceMock(Dictionary.class);
325 expect(dictionary.get("arpEnabled")).andReturn(true).anyTimes();
326 ComponentContext context = createNiceMock(ComponentContext.class);
327 expect(context.getProperties()).andReturn(dictionary).anyTimes();
328
Yi Tseng4025a102017-09-30 11:35:42 +0800329 replay(manager.cfgService, manager.coreService, manager.hostService,
330 manager.compCfgService, dictionary, context);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700331 manager.activate(context);
332 }
333
334 @After
335 public void tearDown() {
336 manager.deactivate();
337 }
338
339 /**
340 * Relay a DHCP packet without option 82.
341 * Should add new host to host store after dhcp ack.
342 */
343 @Test
344 public void relayDhcpWithoutAgentInfo() {
Yi Tsengaa417a62017-09-08 17:22:51 -0700345 replay(mockHostProviderService);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700346 // send request
347 packetService.processPacket(new TestDhcpRequestPacketContext(CLIENT_MAC,
348 CLIENT_VLAN,
349 CLIENT_CP,
350 INTERFACE_IP.ipAddress().getIp4Address(),
351 false));
Yi Tsengaa417a62017-09-08 17:22:51 -0700352 // won't trigger the host provider service
353 verify(mockHostProviderService);
354 reset(mockHostProviderService);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700355
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700356 assertEquals(0, mockRouteStore.routes.size());
357
Yi Tsengaa417a62017-09-08 17:22:51 -0700358 HostId expectHostId = HostId.hostId(CLIENT_MAC, CLIENT_VLAN);
359 Capture<HostDescription> capturedHostDesc = newCapture();
360 mockHostProviderService.hostDetected(eq(expectHostId), capture(capturedHostDesc), eq(false));
361 replay(mockHostProviderService);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700362 // send ack
363 packetService.processPacket(new TestDhcpAckPacketContext(CLIENT_CP, CLIENT_MAC,
364 CLIENT_VLAN, INTERFACE_IP.ipAddress().getIp4Address(),
365 false));
Yi Tsengaa417a62017-09-08 17:22:51 -0700366 verify(mockHostProviderService);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700367 assertEquals(0, mockRouteStore.routes.size());
368
Yi Tsengaa417a62017-09-08 17:22:51 -0700369 HostDescription host = capturedHostDesc.getValue();
370 assertEquals(false, host.configured());
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700371 assertEquals(CLIENT_CP.deviceId(), host.location().elementId());
372 assertEquals(CLIENT_CP.port(), host.location().port());
Yi Tsengaa417a62017-09-08 17:22:51 -0700373 assertEquals(1, host.ipAddress().size());
374 assertEquals(IP_FOR_CLIENT, host.ipAddress().iterator().next());
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700375 }
376
377 /**
378 * Relay a DHCP packet with option 82 (Indirectly connected host).
379 */
380 @Test
381 public void relayDhcpWithAgentInfo() {
Yi Tsengaa417a62017-09-08 17:22:51 -0700382 replay(mockHostProviderService);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700383 // Assume outer dhcp relay agent exists in store already
384 // send request
385 packetService.processPacket(new TestDhcpRequestPacketContext(CLIENT2_MAC,
386 CLIENT2_VLAN,
387 CLIENT2_CP,
388 INTERFACE_IP.ipAddress().getIp4Address(),
389 true));
Yi Tsengaa417a62017-09-08 17:22:51 -0700390 // No routes
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700391 assertEquals(0, mockRouteStore.routes.size());
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700392 // send ack
393 packetService.processPacket(new TestDhcpAckPacketContext(CLIENT2_CP,
394 CLIENT2_MAC,
395 CLIENT2_VLAN,
396 INTERFACE_IP.ipAddress().getIp4Address(),
397 true));
398
Yi Tsengaa417a62017-09-08 17:22:51 -0700399 // won't trigger the host provider service
400 verify(mockHostProviderService);
401 reset(mockHostProviderService);
402
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700403 assertEquals(1, mockRouteStore.routes.size());
404
405 Route route = mockRouteStore.routes.get(0);
406 assertEquals(OUTER_RELAY_IP, route.nextHop());
407 assertEquals(IP_FOR_CLIENT.toIpPrefix(), route.prefix());
408 assertEquals(Route.Source.STATIC, route.source());
409 }
410
411 @Test
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700412 public void testWithRelayAgentConfig() throws DeserializationException {
413 manager.v4Handler
414 .setDefaultDhcpServerConfigs(ImmutableList.of(new MockDhcpServerConfig(RELAY_AGENT_IP)));
Yi Tseng4f2a0462017-08-31 11:21:00 -0700415 manager.v4Handler
416 .setIndirectDhcpServerConfigs(ImmutableList.of(new MockDhcpServerConfig(RELAY_AGENT_IP)));
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700417 packetService.processPacket(new TestDhcpRequestPacketContext(CLIENT2_MAC,
418 CLIENT2_VLAN,
419 CLIENT2_CP,
420 INTERFACE_IP.ipAddress().getIp4Address(),
421 true));
422 OutboundPacket outPacket = packetService.emittedPacket;
423 byte[] outData = outPacket.data().array();
424 Ethernet eth = Ethernet.deserializer().deserialize(outData, 0, outData.length);
425 IPv4 ip = (IPv4) eth.getPayload();
426 UDP udp = (UDP) ip.getPayload();
427 DHCP dhcp = (DHCP) udp.getPayload();
428 assertEquals(RELAY_AGENT_IP.toInt(), dhcp.getGatewayIPAddress());
429 }
430
431 @Test
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700432 public void testArpRequest() throws Exception {
433 packetService.processPacket(new TestArpRequestPacketContext(CLIENT_INTERFACE));
Ray Milkeyc108a6b2017-08-23 15:23:50 -0700434 OutboundPacket outboundPacket = packetService.emittedPacket;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700435 byte[] outPacketData = outboundPacket.data().array();
436 Ethernet eth = Ethernet.deserializer().deserialize(outPacketData, 0, outPacketData.length);
437
438 assertEquals(eth.getEtherType(), Ethernet.TYPE_ARP);
439 ARP arp = (ARP) eth.getPayload();
440 assertArrayEquals(arp.getSenderHardwareAddress(), CLIENT_INTERFACE.mac().toBytes());
441 }
442
Yi Tseng51f1be92017-09-01 17:24:57 -0700443 /**
444 * Ignores specific vlans from specific devices if config.
445 *
446 * @throws Exception the exception from this test
447 */
448 @Test
449 public void testIgnoreVlan() throws Exception {
450 ObjectMapper om = new ObjectMapper();
451 JsonNode json = om.readTree(Resources.getResource(CONFIG_FILE_PATH));
452 IgnoreDhcpConfig config = new IgnoreDhcpConfig();
453 json = json.path("apps").path(DHCP_RELAY_APP).path(IgnoreDhcpConfig.KEY);
454 config.init(APP_ID, IgnoreDhcpConfig.KEY, json, om, null);
455
456 Capture<Objective> capturedFromDev1 = newCapture(CaptureType.ALL);
457 manager.flowObjectiveService.apply(eq(DEV_1_ID), capture(capturedFromDev1));
Yi Tseng127ffe52017-09-12 15:55:17 -0700458 expectLastCall().times(DHCP_SELECTORS.size());
Yi Tseng51f1be92017-09-01 17:24:57 -0700459 Capture<Objective> capturedFromDev2 = newCapture(CaptureType.ALL);
460 manager.flowObjectiveService.apply(eq(DEV_2_ID), capture(capturedFromDev2));
Yi Tseng127ffe52017-09-12 15:55:17 -0700461 expectLastCall().times(DHCP_SELECTORS.size());
Yi Tseng51f1be92017-09-01 17:24:57 -0700462 replay(manager.flowObjectiveService);
463 manager.updateConfig(config);
464 verify(manager.flowObjectiveService);
465
466 List<Objective> objectivesFromDev1 = capturedFromDev1.getValues();
467 List<Objective> objectivesFromDev2 = capturedFromDev2.getValues();
468
469 assertTrue(objectivesFromDev1.containsAll(objectivesFromDev2));
470 assertTrue(objectivesFromDev2.containsAll(objectivesFromDev1));
471 TrafficTreatment dropTreatment = DefaultTrafficTreatment.emptyTreatment();
472 dropTreatment.clearedDeferred();
473
474 for (int index = 0; index < objectivesFromDev1.size(); index++) {
475 TrafficSelector selector =
476 DefaultTrafficSelector.builder(DhcpRelayManager.DHCP_SELECTORS.get(index))
477 .matchVlanId(IGNORED_VLAN)
478 .build();
479 ForwardingObjective fwd = (ForwardingObjective) objectivesFromDev1.get(index);
480 assertEquals(selector, fwd.selector());
481 assertEquals(dropTreatment, fwd.treatment());
482 assertEquals(IGNORE_CONTROL_PRIORITY, fwd.priority());
483 assertEquals(ForwardingObjective.Flag.VERSATILE, fwd.flag());
484 assertEquals(Objective.Operation.ADD, fwd.op());
Yi Tseng127ffe52017-09-12 15:55:17 -0700485 fwd.context().ifPresent(ctx -> {
486 ctx.onSuccess(fwd);
487 });
Yi Tseng51f1be92017-09-01 17:24:57 -0700488 }
Yi Tseng127ffe52017-09-12 15:55:17 -0700489 objectivesFromDev2.forEach(obj -> obj.context().ifPresent(ctx -> ctx.onSuccess(obj)));
Yi Tseng51f1be92017-09-01 17:24:57 -0700490 assertEquals(2, manager.ignoredVlans.size());
491 }
492
493 /**
494 * "IgnoreVlan" policy should be removed when the config removed.
495 */
496 @Test
497 public void testRemoveIgnoreVlan() {
498 manager.ignoredVlans.put(DEV_1_ID, IGNORED_VLAN);
499 manager.ignoredVlans.put(DEV_2_ID, IGNORED_VLAN);
500 IgnoreDhcpConfig config = new IgnoreDhcpConfig();
501
502 Capture<Objective> capturedFromDev1 = newCapture(CaptureType.ALL);
503 manager.flowObjectiveService.apply(eq(DEV_1_ID), capture(capturedFromDev1));
Yi Tseng127ffe52017-09-12 15:55:17 -0700504 expectLastCall().times(DHCP_SELECTORS.size());
Yi Tseng51f1be92017-09-01 17:24:57 -0700505 Capture<Objective> capturedFromDev2 = newCapture(CaptureType.ALL);
506 manager.flowObjectiveService.apply(eq(DEV_2_ID), capture(capturedFromDev2));
Yi Tseng127ffe52017-09-12 15:55:17 -0700507 expectLastCall().times(DHCP_SELECTORS.size());
Yi Tseng51f1be92017-09-01 17:24:57 -0700508 replay(manager.flowObjectiveService);
509 manager.removeConfig(config);
510 verify(manager.flowObjectiveService);
511
512 List<Objective> objectivesFromDev1 = capturedFromDev1.getValues();
513 List<Objective> objectivesFromDev2 = capturedFromDev2.getValues();
514
515 assertTrue(objectivesFromDev1.containsAll(objectivesFromDev2));
516 assertTrue(objectivesFromDev2.containsAll(objectivesFromDev1));
517 TrafficTreatment dropTreatment = DefaultTrafficTreatment.emptyTreatment();
518 dropTreatment.clearedDeferred();
519
520 for (int index = 0; index < objectivesFromDev1.size(); index++) {
521 TrafficSelector selector =
522 DefaultTrafficSelector.builder(DhcpRelayManager.DHCP_SELECTORS.get(index))
523 .matchVlanId(IGNORED_VLAN)
524 .build();
525 ForwardingObjective fwd = (ForwardingObjective) objectivesFromDev1.get(index);
526 assertEquals(selector, fwd.selector());
527 assertEquals(dropTreatment, fwd.treatment());
528 assertEquals(IGNORE_CONTROL_PRIORITY, fwd.priority());
529 assertEquals(ForwardingObjective.Flag.VERSATILE, fwd.flag());
530 assertEquals(Objective.Operation.REMOVE, fwd.op());
Yi Tseng127ffe52017-09-12 15:55:17 -0700531 fwd.context().ifPresent(ctx -> {
532 ctx.onSuccess(fwd);
533 });
Yi Tseng51f1be92017-09-01 17:24:57 -0700534 }
Yi Tseng127ffe52017-09-12 15:55:17 -0700535 objectivesFromDev2.forEach(obj -> obj.context().ifPresent(ctx -> ctx.onSuccess(obj)));
Yi Tseng51f1be92017-09-01 17:24:57 -0700536 assertEquals(0, manager.ignoredVlans.size());
537 }
538
Kalhee Kim45fede42017-09-05 19:05:06 +0000539 /**
Yi Tseng127ffe52017-09-12 15:55:17 -0700540 * Should ignore ignore rules installation when device not available.
541 */
542 @Test
543 public void testIgnoreUnknownDevice() throws IOException {
544 reset(manager.deviceService);
545 Device device = createNiceMock(Device.class);
546 expect(device.is(Pipeliner.class)).andReturn(true).anyTimes();
547
548 expect(manager.deviceService.getDevice(DEV_1_ID)).andReturn(device).anyTimes();
549 expect(manager.deviceService.getDevice(DEV_2_ID)).andReturn(null).anyTimes();
550
551 ObjectMapper om = new ObjectMapper();
552 JsonNode json = om.readTree(Resources.getResource(CONFIG_FILE_PATH));
553 IgnoreDhcpConfig config = new IgnoreDhcpConfig();
554 json = json.path("apps").path(DHCP_RELAY_APP).path(IgnoreDhcpConfig.KEY);
555 config.init(APP_ID, IgnoreDhcpConfig.KEY, json, om, null);
556
557 Capture<Objective> capturedFromDev1 = newCapture(CaptureType.ALL);
558 manager.flowObjectiveService.apply(eq(DEV_1_ID), capture(capturedFromDev1));
559 expectLastCall().times(DHCP_SELECTORS.size());
560 replay(manager.flowObjectiveService, manager.deviceService, device);
561
562 manager.updateConfig(config);
563 capturedFromDev1.getValues().forEach(obj -> obj.context().ifPresent(ctx -> ctx.onSuccess(obj)));
564
565 assertEquals(1, manager.ignoredVlans.size());
566 }
567
568 /**
569 * Should try install ignore rules when device comes up.
570 */
571 @Test
572 public void testInstallIgnoreRuleWhenDeviceComesUp() throws IOException {
573 ObjectMapper om = new ObjectMapper();
574 JsonNode json = om.readTree(Resources.getResource(CONFIG_FILE_PATH));
575 IgnoreDhcpConfig config = new IgnoreDhcpConfig();
576 json = json.path("apps").path(DHCP_RELAY_APP).path(IgnoreDhcpConfig.KEY);
577 config.init(APP_ID, IgnoreDhcpConfig.KEY, json, om, null);
578
579 reset(manager.cfgService, manager.flowObjectiveService, manager.deviceService);
580 expect(manager.cfgService.getConfig(APP_ID, IgnoreDhcpConfig.class))
581 .andReturn(config).anyTimes();
582
583 Device device = createNiceMock(Device.class);
584 expect(device.is(Pipeliner.class)).andReturn(true).anyTimes();
585 expect(device.id()).andReturn(DEV_1_ID).anyTimes();
586 expect(manager.deviceService.getDevice(DEV_1_ID)).andReturn(device).anyTimes();
587 DeviceEvent event = new DeviceEvent(DeviceEvent.Type.DEVICE_ADDED, device);
588 Capture<Objective> capturedFromDev1 = newCapture(CaptureType.ALL);
589 manager.flowObjectiveService.apply(eq(DEV_1_ID), capture(capturedFromDev1));
590 expectLastCall().times(DHCP_SELECTORS.size());
591 replay(manager.cfgService, manager.flowObjectiveService, manager.deviceService, device);
592 assertEquals(0, manager.ignoredVlans.size());
593 manager.deviceListener.event(event);
594 capturedFromDev1.getValues().forEach(obj -> obj.context().ifPresent(ctx -> ctx.onSuccess(obj)));
595 assertEquals(1, manager.ignoredVlans.size());
596 }
597
598 /**
Kalhee Kim45fede42017-09-05 19:05:06 +0000599 * Relay a DHCP6 packet without relay option
600 * Note: Should add new host to host store after dhcp ack.
601 */
602 @Test
603 public void relayDhcp6WithoutAgentInfo() {
Yi Tsengaa417a62017-09-08 17:22:51 -0700604 replay(mockHostProviderService);
Kalhee Kim45fede42017-09-05 19:05:06 +0000605 // send request
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000606 packetService.processPacket(new TestDhcp6RequestPacketContext(DHCP6.MsgType.REQUEST.value(),
607 CLIENT_MAC,
608 CLIENT_VLAN,
Kalhee Kim45fede42017-09-05 19:05:06 +0000609 CLIENT_CP,
610 INTERFACE_IP_V6.ipAddress().getIp6Address(),
611 0));
612
Yi Tsengaa417a62017-09-08 17:22:51 -0700613 verify(mockHostProviderService);
614 reset(mockHostProviderService);
Kalhee Kim45fede42017-09-05 19:05:06 +0000615 assertEquals(0, mockRouteStore.routes.size());
616
Yi Tsengaa417a62017-09-08 17:22:51 -0700617 Capture<HostDescription> capturedHostDesc = newCapture();
618 mockHostProviderService.hostDetected(eq(HostId.hostId(CLIENT_MAC, CLIENT_VLAN)),
619 capture(capturedHostDesc), eq(false));
620 replay(mockHostProviderService);
Kalhee Kim45fede42017-09-05 19:05:06 +0000621 // send reply
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000622 packetService.processPacket(new TestDhcp6ReplyPacketContext(DHCP6.MsgType.REPLY.value(),
623 CLIENT_CP, CLIENT_MAC,
Kalhee Kim45fede42017-09-05 19:05:06 +0000624 CLIENT_VLAN,
625 INTERFACE_IP_V6.ipAddress().getIp6Address(),
626 0));
Yi Tsengaa417a62017-09-08 17:22:51 -0700627 verify(mockHostProviderService);
Kalhee Kim45fede42017-09-05 19:05:06 +0000628 assertEquals(0, mockRouteStore.routes.size());
629
Yi Tsengaa417a62017-09-08 17:22:51 -0700630 HostDescription host = capturedHostDesc.getValue();
Kalhee Kim45fede42017-09-05 19:05:06 +0000631 assertEquals(CLIENT_VLAN, host.vlan());
632 assertEquals(CLIENT_CP.deviceId(), host.location().elementId());
633 assertEquals(CLIENT_CP.port(), host.location().port());
Yi Tsengaa417a62017-09-08 17:22:51 -0700634 assertEquals(1, host.ipAddress().size());
635 assertEquals(IP_FOR_CLIENT_V6, host.ipAddress().iterator().next());
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000636
637 // send release
638 packetService.processPacket(new TestDhcp6RequestPacketContext(DHCP6.MsgType.RELEASE.value(),
639 CLIENT_MAC,
640 CLIENT_VLAN,
641 CLIENT_CP,
642 INTERFACE_IP_V6.ipAddress().getIp6Address(),
643 0));
644
645 assertEquals(null, manager.hostService.getHost(HostId.hostId(CLIENT_MAC, CLIENT_VLAN)));
Kalhee Kim45fede42017-09-05 19:05:06 +0000646 }
647
648 /**
649 * Relay a DHCP6 packet with Relay Message opion (Indirectly connected host).
650 */
651 @Test
652 public void relayDhcp6WithAgentInfo() {
Yi Tsengaa417a62017-09-08 17:22:51 -0700653 replay(mockHostProviderService);
Kalhee Kim45fede42017-09-05 19:05:06 +0000654 // Assume outer dhcp6 relay agent exists in store already
655 // send request
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000656 packetService.processPacket(new TestDhcp6RequestPacketContext(DHCP6.MsgType.REQUEST.value(),
657 CLIENT2_MAC,
658 CLIENT2_VLAN,
659 CLIENT2_CP,
660 OUTER_RELAY_IP_V6,
661 1));
662
663 assertEquals(0, mockRouteStore.routes.size());
664
665 // send reply
666 packetService.processPacket(new TestDhcp6ReplyPacketContext(DHCP6.MsgType.REPLY.value(), CLIENT2_CP,
667 CLIENT2_MAC,
668 CLIENT2_VLAN,
669 OUTER_RELAY_IP_V6,
670 1));
671
672 // won't trigger the host provider service
673 verify(mockHostProviderService);
674 reset(mockHostProviderService);
675 assertEquals(2, mockRouteStore.routes.size()); // ipAddress and prefix
676
677 Route aRoute = mockRouteStore.routes.stream()
678 .filter(rt -> rt.prefix().contains(IP_FOR_CLIENT_V6))
679 .findFirst()
680 .orElse(null);
681 assertNotEquals(null, aRoute);
682
683 aRoute = mockRouteStore.routes.stream()
684 .filter(rt -> rt.prefix().contains(PREFIX_FOR_CLIENT_V6))
685 .findFirst()
686 .orElse(null);
687 assertNotEquals(null, aRoute);
688
689 // send release msg
690 packetService.processPacket(new TestDhcp6RequestPacketContext(DHCP6.MsgType.RELEASE.value(),
691 CLIENT2_MAC,
692 CLIENT2_VLAN,
693 CLIENT2_CP,
694 OUTER_RELAY_IP_V6,
695 1));
696
697 aRoute = mockRouteStore.routes.stream()
698 .filter(rt -> rt.prefix().contains(IP_FOR_CLIENT_V6))
699 .findFirst()
700 .orElse(null);
701 assertEquals(null, aRoute);
702
703 aRoute = mockRouteStore.routes.stream()
704 .filter(rt -> rt.prefix().contains(PREFIX_FOR_CLIENT_V6))
705 .findFirst()
706 .orElse(null);
707 assertEquals(null, aRoute);
708
709 assertEquals(0, mockRouteStore.routes.size());
710
711 }
712
713 /**
714 * Relay a DHCP6 packet with Relay Message opion (Indirectly connected host) and server responded
715 * with vlan differnt from client interface vlan.
716 */
717 @Test
718 public void relayDhcp6WithAgentInfoWrongVlan() {
719 replay(mockHostProviderService);
720 // Assume outer dhcp6 relay agent exists in store already
721 // send request
722 packetService.processPacket(new TestDhcp6RequestPacketContext(DHCP6.MsgType.REQUEST.value(),
723 CLIENT2_MAC,
Kalhee Kim45fede42017-09-05 19:05:06 +0000724 CLIENT2_VLAN,
725 CLIENT2_CP,
726 INTERFACE_IP_V6.ipAddress().getIp6Address(),
727 1));
728
Kalhee Kim45fede42017-09-05 19:05:06 +0000729 assertEquals(0, mockRouteStore.routes.size());
730
731 // send reply
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000732 packetService.processPacket(new TestDhcp6ReplyPacketContext(DHCP6.MsgType.REPLY.value(),
733 CLIENT2_CP,
Kalhee Kim45fede42017-09-05 19:05:06 +0000734 CLIENT2_MAC,
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000735 CLIENT_BOGUS_VLAN, // mismatch
Kalhee Kim45fede42017-09-05 19:05:06 +0000736 INTERFACE_IP_V6.ipAddress().getIp6Address(),
737 1));
738
Yi Tsengaa417a62017-09-08 17:22:51 -0700739 // won't trigger the host provider service
740 verify(mockHostProviderService);
741 reset(mockHostProviderService);
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000742 assertEquals(0, mockRouteStore.routes.size()); // ipAddress and prefix
Kalhee Kim45fede42017-09-05 19:05:06 +0000743
Kalhee Kim45fede42017-09-05 19:05:06 +0000744 }
Yi Tsengaa417a62017-09-08 17:22:51 -0700745
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000746
Yi Tsengaa417a62017-09-08 17:22:51 -0700747 @Test
748 public void testDhcp4DualHome() {
749 PacketContext packetContext =
750 new TestDhcpAckPacketContext(CLIENT_DH_CP, CLIENT_MAC, CLIENT_VLAN,
751 INTERFACE_IP.ipAddress().getIp4Address(),
752 false);
753 reset(manager.hostService);
754 expect(manager.hostService.getHost(CLIENT_HOST_ID)).andReturn(EXISTS_HOST).anyTimes();
755 Capture<HostDescription> capturedHostDesc = newCapture();
756 mockHostProviderService.hostDetected(eq(CLIENT_HOST_ID), capture(capturedHostDesc), eq(false));
757 replay(mockHostProviderService, manager.hostService);
758 packetService.processPacket(packetContext);
759 verify(mockHostProviderService);
760
761 HostDescription hostDesc = capturedHostDesc.getValue();
762 Set<HostLocation> hostLocations = hostDesc.locations();
763 assertEquals(2, hostLocations.size());
764 assertTrue(hostLocations.contains(CLIENT_LOCATION));
765 assertTrue(hostLocations.contains(CLIENT_DH_LOCATION));
766 }
767
768 @Test
769 public void testDhcp6DualHome() {
770 PacketContext packetContext =
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000771 new TestDhcp6ReplyPacketContext(DHCP6.MsgType.REPLY.value(),
772 CLIENT_DH_CP, CLIENT_MAC, CLIENT_VLAN,
Yi Tsengaa417a62017-09-08 17:22:51 -0700773 INTERFACE_IP_V6.ipAddress().getIp6Address(),
774 0);
775 reset(manager.hostService);
776 expect(manager.hostService.getHostsByIp(CLIENT_LL_IP_V6)).andReturn(ImmutableSet.of(EXISTS_HOST)).anyTimes();
777
778 // FIXME: currently DHCPv6 has a bug, we can't get correct vlan of client......
779 // XXX: The vlan relied from DHCP6 handler might be wrong, do hack here
780 HostId hostId = HostId.hostId(CLIENT_MAC, VlanId.NONE);
781 expect(manager.hostService.getHost(hostId)).andReturn(EXISTS_HOST).anyTimes();
782
783 // XXX: sometimes this will work, sometimes not
784 expect(manager.hostService.getHost(CLIENT_HOST_ID)).andReturn(EXISTS_HOST).anyTimes();
785
786 Capture<HostDescription> capturedHostDesc = newCapture();
787
788 // XXX: also a hack here
789 mockHostProviderService.hostDetected(eq(hostId), capture(capturedHostDesc), eq(false));
790 expectLastCall().anyTimes();
791
792 mockHostProviderService.hostDetected(eq(CLIENT_HOST_ID), capture(capturedHostDesc), eq(false));
793 expectLastCall().anyTimes();
794 replay(mockHostProviderService, manager.hostService);
795 packetService.processPacket(packetContext);
796 verify(mockHostProviderService);
797
798 HostDescription hostDesc = capturedHostDesc.getValue();
799 Set<HostLocation> hostLocations = hostDesc.locations();
800 assertEquals(2, hostLocations.size());
801 assertTrue(hostLocations.contains(CLIENT_LOCATION));
802 assertTrue(hostLocations.contains(CLIENT_DH_LOCATION));
803 }
804
Yi Tseng483ac6f2017-08-02 15:03:31 -0700805 private static class MockDefaultDhcpRelayConfig extends DefaultDhcpRelayConfig {
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700806 @Override
807 public boolean isValid() {
808 return true;
809 }
810
811 @Override
Yi Tseng483ac6f2017-08-02 15:03:31 -0700812 public List<DhcpServerConfig> dhcpServerConfigs() {
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700813 return ImmutableList.of(new MockDhcpServerConfig(null));
Yi Tseng483ac6f2017-08-02 15:03:31 -0700814 }
815 }
816
Kalhee Kim45fede42017-09-05 19:05:06 +0000817 private static class MockIndirectDhcpRelayConfig extends IndirectDhcpRelayConfig {
818 @Override
819 public boolean isValid() {
820 return true;
821 }
822
823 @Override
824 public List<DhcpServerConfig> dhcpServerConfigs() {
825 return ImmutableList.of(new MockDhcpServerConfig(null));
826 }
827 }
828
Yi Tseng483ac6f2017-08-02 15:03:31 -0700829 private static class MockDhcpServerConfig extends DhcpServerConfig {
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700830 Ip4Address relayAgentIp;
831
832 /**
833 * Create mocked version DHCP server config.
834 *
835 * @param relayAgentIp the relay agent Ip config; null if we don't need it
836 */
837 public MockDhcpServerConfig(Ip4Address relayAgentIp) {
838 this.relayAgentIp = relayAgentIp;
839 }
840
841 @Override
842 public Optional<Ip4Address> getRelayAgentIp4() {
843 return Optional.ofNullable(relayAgentIp);
844 }
845
Yi Tseng483ac6f2017-08-02 15:03:31 -0700846 @Override
847 public Optional<ConnectPoint> getDhcpServerConnectPoint() {
848 return Optional.of(SERVER_CONNECT_POINT);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700849 }
850
Yi Tseng483ac6f2017-08-02 15:03:31 -0700851 @Override
852 public Optional<Ip4Address> getDhcpServerIp4() {
853 return Optional.of(SERVER_IP);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700854 }
Kalhee Kim45fede42017-09-05 19:05:06 +0000855
856 @Override
857 public Optional<Ip4Address> getDhcpGatewayIp4() {
858 return Optional.of(GATEWAY_IP);
859 }
860
861 @Override
862 public Optional<Ip6Address> getDhcpServerIp6() {
863 return Optional.of(SERVER_IP_V6);
864 }
865
866 @Override
867 public Optional<Ip6Address> getDhcpGatewayIp6() {
868 return Optional.of(GATEWAY_IP_V6);
869 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700870 }
871
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700872 private class MockRouteStore extends RouteStoreAdapter {
873 private List<Route> routes = Lists.newArrayList();
874
875 @Override
876 public void updateRoute(Route route) {
877 routes.add(route);
878 }
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000879
880 @Override
881 public void removeRoute(Route route) {
882 routes.remove(route);
883 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700884 }
885
886 private class MockInterfaceService extends InterfaceServiceAdapter {
887
888 @Override
889 public Set<Interface> getInterfaces() {
890 return INTERFACES;
891 }
892
893 @Override
894 public Set<Interface> getInterfacesByIp(IpAddress ip) {
895 return INTERFACES.stream()
896 .filter(iface -> {
897 return iface.ipAddressesList().stream()
898 .anyMatch(ifaceIp -> ifaceIp.ipAddress().equals(ip));
899 })
900 .collect(Collectors.toSet());
901 }
902
903 @Override
904 public Set<Interface> getInterfacesByPort(ConnectPoint port) {
905 return INTERFACES.stream()
906 .filter(iface -> iface.connectPoint().equals(port))
907 .collect(Collectors.toSet());
908 }
909 }
910
911 private class MockDhcpRelayStore implements DhcpRelayStore {
912 StoreDelegate<DhcpRelayStoreEvent> delegate;
913 private Map<HostId, DhcpRecord> records = Maps.newHashMap();
914
915 @Override
916 public void updateDhcpRecord(HostId hostId, DhcpRecord dhcpRecord) {
917 records.put(hostId, dhcpRecord);
918 DhcpRelayStoreEvent event = new DhcpRelayStoreEvent(DhcpRelayStoreEvent.Type.UPDATED,
919 dhcpRecord);
920 if (delegate != null) {
921 delegate.notify(event);
922 }
923 }
924
925 @Override
926 public Optional<DhcpRecord> getDhcpRecord(HostId hostId) {
927 return Optional.ofNullable(records.get(hostId));
928 }
929
930 @Override
931 public Collection<DhcpRecord> getDhcpRecords() {
932 return records.values();
933 }
934
935 @Override
936 public Optional<DhcpRecord> removeDhcpRecord(HostId hostId) {
937 DhcpRecord dhcpRecord = records.remove(hostId);
938 if (dhcpRecord != null) {
939 DhcpRelayStoreEvent event = new DhcpRelayStoreEvent(DhcpRelayStoreEvent.Type.REMOVED,
940 dhcpRecord);
941 if (delegate != null) {
942 delegate.notify(event);
943 }
944 }
945 return Optional.ofNullable(dhcpRecord);
946 }
947
948 @Override
949 public void setDelegate(StoreDelegate<DhcpRelayStoreEvent> delegate) {
950 this.delegate = delegate;
951 }
952
953 @Override
954 public void unsetDelegate(StoreDelegate<DhcpRelayStoreEvent> delegate) {
955 this.delegate = null;
956 }
957
958 @Override
959 public boolean hasDelegate() {
960 return this.delegate != null;
961 }
962 }
963
964 private class MockPacketService extends PacketServiceAdapter {
965 Set<PacketProcessor> packetProcessors = Sets.newHashSet();
Ray Milkeyc108a6b2017-08-23 15:23:50 -0700966 OutboundPacket emittedPacket;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700967
968 @Override
969 public void addProcessor(PacketProcessor processor, int priority) {
970 packetProcessors.add(processor);
971 }
972
973 public void processPacket(PacketContext packetContext) {
974 packetProcessors.forEach(p -> p.process(packetContext));
975 }
976
977 @Override
978 public void emit(OutboundPacket packet) {
Ray Milkeyc108a6b2017-08-23 15:23:50 -0700979 this.emittedPacket = packet;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700980 }
981 }
982
983
984
985 /**
986 * Generates DHCP REQUEST packet.
987 */
988 private class TestDhcpRequestPacketContext extends PacketContextAdapter {
989
990
991 private InboundPacket inPacket;
992
993 public TestDhcpRequestPacketContext(MacAddress clientMac, VlanId vlanId,
994 ConnectPoint clientCp,
995 Ip4Address clientGwAddr,
996 boolean withNonOnosRelayInfo) {
997 super(0, null, null, false);
998 byte[] dhcpMsgType = new byte[1];
999 dhcpMsgType[0] = (byte) DHCP.MsgType.DHCPREQUEST.getValue();
1000
1001 DhcpOption dhcpOption = new DhcpOption();
1002 dhcpOption.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue());
1003 dhcpOption.setData(dhcpMsgType);
1004 dhcpOption.setLength((byte) 1);
1005 DhcpOption endOption = new DhcpOption();
1006 endOption.setCode(DHCP.DHCPOptionCode.OptionCode_END.getValue());
1007
1008 DHCP dhcp = new DHCP();
1009 dhcp.setHardwareType(DHCP.HWTYPE_ETHERNET);
1010 dhcp.setHardwareAddressLength((byte) 6);
1011 dhcp.setClientHardwareAddress(clientMac.toBytes());
1012 if (withNonOnosRelayInfo) {
1013 DhcpRelayAgentOption relayOption = new DhcpRelayAgentOption();
1014 DhcpOption circuitIdOption = new DhcpOption();
1015 CircuitId circuitId = new CircuitId("Custom option", VlanId.NONE);
1016 byte[] cid = circuitId.serialize();
1017 circuitIdOption.setCode(DhcpRelayAgentOption.RelayAgentInfoOptions.CIRCUIT_ID.getValue());
1018 circuitIdOption.setLength((byte) cid.length);
1019 circuitIdOption.setData(cid);
1020 relayOption.setCode(DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue());
1021 relayOption.addSubOption(circuitIdOption);
1022 dhcp.setOptions(ImmutableList.of(dhcpOption, relayOption, endOption));
1023 dhcp.setGatewayIPAddress(OUTER_RELAY_IP.getIp4Address().toInt());
1024 } else {
1025 dhcp.setOptions(ImmutableList.of(dhcpOption, endOption));
1026 }
1027
1028
1029 UDP udp = new UDP();
1030 udp.setPayload(dhcp);
1031 udp.setSourcePort(UDP.DHCP_CLIENT_PORT);
1032 udp.setDestinationPort(UDP.DHCP_SERVER_PORT);
1033
1034 IPv4 ipv4 = new IPv4();
1035 ipv4.setPayload(udp);
1036 ipv4.setDestinationAddress(SERVER_IP.toInt());
1037 ipv4.setSourceAddress(clientGwAddr.toInt());
1038
1039 Ethernet eth = new Ethernet();
1040 if (withNonOnosRelayInfo) {
1041 eth.setEtherType(Ethernet.TYPE_IPV4)
1042 .setVlanID(vlanId.toShort())
1043 .setSourceMACAddress(OUTER_RELAY_MAC)
1044 .setDestinationMACAddress(MacAddress.BROADCAST)
1045 .setPayload(ipv4);
1046 } else {
1047 eth.setEtherType(Ethernet.TYPE_IPV4)
1048 .setVlanID(vlanId.toShort())
1049 .setSourceMACAddress(clientMac)
1050 .setDestinationMACAddress(MacAddress.BROADCAST)
1051 .setPayload(ipv4);
1052 }
1053
1054 this.inPacket = new DefaultInboundPacket(clientCp, eth,
1055 ByteBuffer.wrap(eth.serialize()));
1056 }
1057
1058 @Override
1059 public InboundPacket inPacket() {
1060 return this.inPacket;
1061 }
1062 }
1063
1064 /**
1065 * Generates DHCP ACK packet.
1066 */
1067 private class TestDhcpAckPacketContext extends PacketContextAdapter {
1068 private InboundPacket inPacket;
1069
1070 public TestDhcpAckPacketContext(ConnectPoint clientCp, MacAddress clientMac,
1071 VlanId clientVlan, Ip4Address clientGwAddr,
1072 boolean withNonOnosRelayInfo) {
1073 super(0, null, null, false);
1074
1075 byte[] dhcpMsgType = new byte[1];
1076 dhcpMsgType[0] = (byte) DHCP.MsgType.DHCPACK.getValue();
1077
1078 DhcpOption dhcpOption = new DhcpOption();
1079 dhcpOption.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue());
1080 dhcpOption.setData(dhcpMsgType);
1081 dhcpOption.setLength((byte) 1);
1082
1083 DhcpOption endOption = new DhcpOption();
1084 endOption.setCode(DHCP.DHCPOptionCode.OptionCode_END.getValue());
1085
1086 DHCP dhcp = new DHCP();
1087 if (withNonOnosRelayInfo) {
1088 DhcpRelayAgentOption relayOption = new DhcpRelayAgentOption();
1089 DhcpOption circuitIdOption = new DhcpOption();
Yi Tseng440e2b72017-08-24 14:47:34 -07001090 String circuitId = NON_ONOS_CID;
1091 byte[] cid = circuitId.getBytes(Charsets.US_ASCII);
Yi Tseng7a38f9a2017-06-09 14:36:40 -07001092 circuitIdOption.setCode(DhcpRelayAgentOption.RelayAgentInfoOptions.CIRCUIT_ID.getValue());
1093 circuitIdOption.setLength((byte) cid.length);
1094 circuitIdOption.setData(cid);
1095 relayOption.setCode(DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue());
1096 relayOption.addSubOption(circuitIdOption);
1097 dhcp.setOptions(ImmutableList.of(dhcpOption, relayOption, endOption));
1098 dhcp.setGatewayIPAddress(OUTER_RELAY_IP.getIp4Address().toInt());
1099 } else {
1100 CircuitId cid = new CircuitId(clientCp.toString(), clientVlan);
1101 byte[] circuitId = cid.serialize();
1102 DhcpOption circuitIdSubOption = new DhcpOption();
1103 circuitIdSubOption.setCode(DhcpRelayAgentOption.RelayAgentInfoOptions.CIRCUIT_ID.getValue());
1104 circuitIdSubOption.setData(circuitId);
1105 circuitIdSubOption.setLength((byte) circuitId.length);
1106
1107 DhcpRelayAgentOption relayInfoOption = new DhcpRelayAgentOption();
1108 relayInfoOption.setCode(DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue());
1109 relayInfoOption.addSubOption(circuitIdSubOption);
1110 dhcp.setOptions(ImmutableList.of(dhcpOption, relayInfoOption, endOption));
1111 dhcp.setGatewayIPAddress(clientGwAddr.toInt());
1112 }
1113 dhcp.setHardwareType(DHCP.HWTYPE_ETHERNET);
1114 dhcp.setHardwareAddressLength((byte) 6);
1115 dhcp.setClientHardwareAddress(clientMac.toBytes());
1116 dhcp.setYourIPAddress(IP_FOR_CLIENT.toInt());
1117
1118 UDP udp = new UDP();
1119 udp.setPayload(dhcp);
1120 udp.setSourcePort(UDP.DHCP_SERVER_PORT);
1121 udp.setDestinationPort(UDP.DHCP_CLIENT_PORT);
1122 IPv4 ipv4 = new IPv4();
1123 ipv4.setPayload(udp);
1124 ipv4.setDestinationAddress(IP_FOR_CLIENT.toString());
1125 ipv4.setSourceAddress(SERVER_IP.toString());
1126 Ethernet eth = new Ethernet();
1127 if (withNonOnosRelayInfo) {
1128 eth.setEtherType(Ethernet.TYPE_IPV4)
1129 .setVlanID(SERVER_VLAN.toShort())
1130 .setSourceMACAddress(SERVER_MAC)
1131 .setDestinationMACAddress(OUTER_RELAY_MAC)
1132 .setPayload(ipv4);
1133 } else {
1134 eth.setEtherType(Ethernet.TYPE_IPV4)
1135 .setVlanID(SERVER_VLAN.toShort())
1136 .setSourceMACAddress(SERVER_MAC)
1137 .setDestinationMACAddress(CLIENT_MAC)
1138 .setPayload(ipv4);
1139 }
1140
1141 this.inPacket = new DefaultInboundPacket(SERVER_CONNECT_POINT, eth,
1142 ByteBuffer.wrap(eth.serialize()));
1143
1144 }
1145
1146 @Override
1147 public InboundPacket inPacket() {
1148 return this.inPacket;
1149 }
1150 }
1151
1152 private class TestArpRequestPacketContext extends PacketContextAdapter {
1153 private InboundPacket inPacket;
1154
1155 public TestArpRequestPacketContext(Interface fromInterface) {
1156 super(0, null, null, false);
1157 ARP arp = new ARP();
1158 arp.setOpCode(ARP.OP_REQUEST);
1159
1160 IpAddress targetIp = fromInterface.ipAddressesList().get(0).ipAddress();
1161 arp.setTargetProtocolAddress(targetIp.toOctets());
1162 arp.setTargetHardwareAddress(MacAddress.BROADCAST.toBytes());
1163 arp.setSenderHardwareAddress(MacAddress.NONE.toBytes());
1164 arp.setSenderProtocolAddress(Ip4Address.valueOf(0).toOctets());
1165 arp.setHardwareAddressLength((byte) MacAddress.MAC_ADDRESS_LENGTH);
1166 Ethernet eth = new Ethernet();
1167 eth.setEtherType(Ethernet.TYPE_ARP);
1168 eth.setSourceMACAddress(MacAddress.NONE);
1169 eth.setDestinationMACAddress(MacAddress.BROADCAST);
1170 eth.setVlanID(fromInterface.vlan().toShort());
1171 eth.setPayload(arp);
1172
1173 this.inPacket = new DefaultInboundPacket(fromInterface.connectPoint(), eth,
1174 ByteBuffer.wrap(eth.serialize()));
1175 }
1176
1177 @Override
1178 public InboundPacket inPacket() {
1179 return this.inPacket;
1180 }
1181 }
Kalhee Kim45fede42017-09-05 19:05:06 +00001182
1183 /**
1184 * Generates DHCP6 REQUEST packet.
1185 */
1186 private void buildDhcp6Packet(DHCP6 dhcp6, byte msgType, Ip6Address ip6Addr, IpPrefix prefix) {
1187
1188 // build address option
1189 Dhcp6IaAddressOption iaAddressOption = new Dhcp6IaAddressOption();
1190 iaAddressOption.setCode(DHCP6.OptionCode.IAADDR.value());
1191 iaAddressOption.setIp6Address(ip6Addr);
1192 iaAddressOption.setPreferredLifetime(3600);
1193 iaAddressOption.setValidLifetime(1200);
1194 iaAddressOption.setLength((short) Dhcp6IaAddressOption.DEFAULT_LEN);
1195
1196 Dhcp6IaNaOption iaNaOption = new Dhcp6IaNaOption();
1197 iaNaOption.setCode(DHCP6.OptionCode.IA_NA.value());
1198 iaNaOption.setIaId(0);
1199 iaNaOption.setT1(302400);
1200 iaNaOption.setT2(483840);
1201 List<Dhcp6Option> iaNaSubOptions = new ArrayList<Dhcp6Option>();
1202 iaNaSubOptions.add(iaAddressOption);
1203 iaNaOption.setOptions(iaNaSubOptions);
1204 iaNaOption.setLength((short) (Dhcp6IaNaOption.DEFAULT_LEN + iaAddressOption.getLength()));
1205
1206 // build prefix option
1207 Dhcp6IaPrefixOption iaPrefixOption = new Dhcp6IaPrefixOption();
1208 iaPrefixOption.setCode(DHCP6.OptionCode.IAPREFIX.value());
1209 iaPrefixOption.setIp6Prefix(prefix.address().getIp6Address());
1210 iaPrefixOption.setPrefixLength((byte) prefix.prefixLength());
1211 iaPrefixOption.setPreferredLifetime(3601);
1212 iaPrefixOption.setValidLifetime(1201);
1213 iaPrefixOption.setLength((short) Dhcp6IaPrefixOption.DEFAULT_LEN);
1214
1215 Dhcp6IaPdOption iaPdOption = new Dhcp6IaPdOption();
1216 iaPdOption.setCode(DHCP6.OptionCode.IA_PD.value());
1217 iaPdOption.setIaId(0);
1218 iaPdOption.setT1(302401);
1219 iaPdOption.setT2(483841);
1220 List<Dhcp6Option> iaPdSubOptions = new ArrayList<Dhcp6Option>();
1221 iaPdSubOptions.add(iaPrefixOption);
1222 iaPdOption.setOptions(iaPdSubOptions);
1223 iaPdOption.setLength((short) (Dhcp6IaPdOption.DEFAULT_LEN + iaPrefixOption.getLength()));
1224
1225 dhcp6.setMsgType(msgType);
1226 List<Dhcp6Option> dhcp6Options = new ArrayList<Dhcp6Option>();
1227 dhcp6Options.add(iaNaOption);
1228 dhcp6Options.add(iaPdOption);
1229 dhcp6.setOptions(dhcp6Options);
1230
1231 }
1232
1233 private void buildRelayMsg(DHCP6 dhcp6Relay, byte msgType, Ip6Address linkAddr,
1234 Ip6Address peerAddr, byte hop, byte[] interfaceIdBytes,
1235 DHCP6 dhcp6Payload) {
1236
1237 dhcp6Relay.setMsgType(msgType);
1238
1239 dhcp6Relay.setLinkAddress(linkAddr.toOctets());
1240 dhcp6Relay.setPeerAddress(peerAddr.toOctets());
1241 dhcp6Relay.setHopCount(hop);
1242 List<Dhcp6Option> options = new ArrayList<Dhcp6Option>();
1243
1244 // interfaceId option
1245 Dhcp6Option interfaceId = new Dhcp6Option();
1246 interfaceId.setCode(DHCP6.OptionCode.INTERFACE_ID.value());
1247
1248
1249 interfaceId.setData(interfaceIdBytes);
1250 interfaceId.setLength((short) interfaceIdBytes.length);
1251 Dhcp6InterfaceIdOption interfaceIdOption = new Dhcp6InterfaceIdOption(interfaceId);
Kalhee Kima0b8f652017-10-18 22:00:30 +00001252 byte[] optionData = interfaceIdOption.getData();
Kalhee Kim45fede42017-09-05 19:05:06 +00001253 ByteBuffer bb = ByteBuffer.wrap(interfaceIdBytes);
1254
1255 byte[] macAddr = new byte[MacAddress.MAC_ADDRESS_LENGTH];
Kalhee Kima0b8f652017-10-18 22:00:30 +00001256 byte[] port = new byte[optionData.length - MacAddress.MAC_ADDRESS_LENGTH -
1257 VLAN_LEN - SEPARATOR_LEN * 2];
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001258 short vlan;
Kalhee Kim45fede42017-09-05 19:05:06 +00001259 bb.get(macAddr);
1260 bb.get(); // separator
1261 bb.get(port);
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001262 bb.get(); // separator
1263 vlan = bb.getShort();
Kalhee Kim45fede42017-09-05 19:05:06 +00001264 interfaceIdOption.setMacAddress(MacAddress.valueOf(macAddr));
1265 interfaceIdOption.setInPort(port);
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001266 interfaceIdOption.setVlanId(vlan);
Kalhee Kim45fede42017-09-05 19:05:06 +00001267
1268 options.add(interfaceIdOption);
1269
1270 // relay message option
1271 Dhcp6Option relayMsgOption = new Dhcp6Option();
1272 relayMsgOption.setCode(DHCP6.OptionCode.RELAY_MSG.value());
1273 byte[] dhcp6PayloadByte = dhcp6Payload.serialize();
1274 relayMsgOption.setLength((short) dhcp6PayloadByte.length);
1275 relayMsgOption.setPayload(dhcp6Payload);
1276 Dhcp6RelayOption relayOpt = new Dhcp6RelayOption(relayMsgOption);
1277
1278 options.add(relayOpt);
1279
1280 dhcp6Relay.setOptions(options);
1281 }
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001282 private byte[] buildInterfaceId(MacAddress clientMac, short vlanId, ConnectPoint clientCp) {
1283 String inPortString = "-" + clientCp.toString() + ":";
Kalhee Kim45fede42017-09-05 19:05:06 +00001284 byte[] clientSoureMacBytes = clientMac.toBytes();
1285 byte[] inPortStringBytes = inPortString.getBytes();
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001286 byte[] vlanIdBytes = new byte[2];
1287 vlanIdBytes[0] = (byte) ((vlanId >> 8) & 0xff); // high-order byte first
1288 vlanIdBytes[1] = (byte) (vlanId & 0xff);
1289 byte[] interfaceIdBytes = new byte[clientSoureMacBytes.length + inPortStringBytes.length + vlanIdBytes.length];
Kalhee Kim45fede42017-09-05 19:05:06 +00001290
1291 System.arraycopy(clientSoureMacBytes, 0, interfaceIdBytes, 0, clientSoureMacBytes.length);
1292 System.arraycopy(inPortStringBytes, 0, interfaceIdBytes, clientSoureMacBytes.length, inPortStringBytes.length);
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001293 System.arraycopy(vlanIdBytes, 0, interfaceIdBytes, clientSoureMacBytes.length + inPortStringBytes.length,
1294 vlanIdBytes.length);
Kalhee Kim45fede42017-09-05 19:05:06 +00001295
1296 return interfaceIdBytes;
1297 }
1298
1299 private class TestDhcp6RequestPacketContext extends PacketContextAdapter {
1300
1301
1302 private InboundPacket inPacket;
1303
1304
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001305 public TestDhcp6RequestPacketContext(byte msgType, MacAddress clientMac, VlanId vlanId,
Kalhee Kim45fede42017-09-05 19:05:06 +00001306 ConnectPoint clientCp,
1307 Ip6Address clientGwAddr,
1308 int relayLevel) {
1309 super(0, null, null, false);
1310
1311 DHCP6 dhcp6 = new DHCP6();
1312 if (relayLevel > 0) {
1313 DHCP6 dhcp6Payload = new DHCP6();
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001314 buildDhcp6Packet(dhcp6Payload, msgType,
Kalhee Kim45fede42017-09-05 19:05:06 +00001315 IP_FOR_CLIENT_V6,
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001316 msgType == DHCP6.MsgType.REQUEST.value() ? PREFIX_FOR_ZERO : PREFIX_FOR_CLIENT_V6);
Kalhee Kim45fede42017-09-05 19:05:06 +00001317 DHCP6 dhcp6Parent = null;
1318 DHCP6 dhcp6Child = dhcp6Payload;
1319 for (int i = 0; i < relayLevel; i++) {
1320 dhcp6Parent = new DHCP6();
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001321 byte[] interfaceId = buildInterfaceId(clientMac, vlanId.toShort(), clientCp);
Kalhee Kim45fede42017-09-05 19:05:06 +00001322 buildRelayMsg(dhcp6Parent, DHCP6.MsgType.RELAY_FORW.value(),
1323 INTERFACE_IP_V6.ipAddress().getIp6Address(),
1324 OUTER_RELAY_IP_V6,
1325 (byte) (relayLevel - 1), interfaceId,
1326 dhcp6Child);
1327 dhcp6Child = dhcp6Parent;
1328 }
1329 if (dhcp6Parent != null) {
1330 dhcp6 = dhcp6Parent;
1331 }
1332 } else {
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001333 buildDhcp6Packet(dhcp6, msgType,
Kalhee Kim45fede42017-09-05 19:05:06 +00001334 IP_FOR_CLIENT_V6,
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001335 msgType == DHCP6.MsgType.REQUEST.value() ? PREFIX_FOR_ZERO : PREFIX_FOR_CLIENT_V6);
Kalhee Kim45fede42017-09-05 19:05:06 +00001336 }
1337
1338 UDP udp = new UDP();
1339 udp.setPayload(dhcp6);
1340 if (relayLevel > 0) {
1341 udp.setSourcePort(UDP.DHCP_V6_SERVER_PORT);
1342 } else {
1343 udp.setSourcePort(UDP.DHCP_V6_CLIENT_PORT);
1344 }
1345 udp.setDestinationPort(UDP.DHCP_V6_SERVER_PORT);
1346
1347 IPv6 ipv6 = new IPv6();
1348 ipv6.setPayload(udp);
1349 ipv6.setNextHeader(IPv6.PROTOCOL_UDP);
1350 ipv6.setDestinationAddress(SERVER_IP_V6_MCAST.toOctets());
1351 ipv6.setSourceAddress(clientGwAddr.toOctets());
1352
1353 Ethernet eth = new Ethernet();
1354 if (relayLevel > 0) {
1355 eth.setEtherType(Ethernet.TYPE_IPV6)
1356 .setVlanID(vlanId.toShort())
1357 .setSourceMACAddress(OUTER_RELAY_MAC)
1358 .setDestinationMACAddress(MacAddress.valueOf("33:33:00:01:00:02"))
1359 .setPayload(ipv6);
1360 } else {
1361 eth.setEtherType(Ethernet.TYPE_IPV6)
1362 .setVlanID(vlanId.toShort())
1363 .setSourceMACAddress(clientMac)
1364 .setDestinationMACAddress(MacAddress.valueOf("33:33:00:01:00:02"))
1365 .setPayload(ipv6);
1366 }
1367 this.inPacket = new DefaultInboundPacket(clientCp, eth,
1368 ByteBuffer.wrap(eth.serialize()));
1369 }
1370
1371 @Override
1372 public InboundPacket inPacket() {
1373 return this.inPacket;
1374 }
1375 }
1376
1377 /**
1378 * Generates DHCP6 REPLY packet.
1379 */
1380
1381 private class TestDhcp6ReplyPacketContext extends PacketContextAdapter {
1382 private InboundPacket inPacket;
1383
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001384 public TestDhcp6ReplyPacketContext(byte msgType, ConnectPoint clientCp, MacAddress clientMac,
Kalhee Kim45fede42017-09-05 19:05:06 +00001385 VlanId clientVlan, Ip6Address clientGwAddr,
1386 int relayLevel) {
1387 super(0, null, null, false);
1388
1389
1390 DHCP6 dhcp6Payload = new DHCP6();
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001391 buildDhcp6Packet(dhcp6Payload, msgType,
Kalhee Kim45fede42017-09-05 19:05:06 +00001392 IP_FOR_CLIENT_V6,
1393 PREFIX_FOR_CLIENT_V6);
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001394 byte[] interfaceId = buildInterfaceId(clientMac, clientVlan.toShort(), clientCp);
Kalhee Kim45fede42017-09-05 19:05:06 +00001395 DHCP6 dhcp6 = new DHCP6();
1396 buildRelayMsg(dhcp6, DHCP6.MsgType.RELAY_REPL.value(),
Yi Tsengaa417a62017-09-08 17:22:51 -07001397 INTERFACE_IP_V6.ipAddress().getIp6Address(),
1398 CLIENT_LL_IP_V6,
1399 (byte) 0, interfaceId,
1400 dhcp6Payload);
Kalhee Kim45fede42017-09-05 19:05:06 +00001401
1402 DHCP6 dhcp6Parent = null;
1403 DHCP6 dhcp6Child = dhcp6;
1404 for (int i = 0; i < relayLevel; i++) { // relayLevel 0 : no relay
1405 dhcp6Parent = new DHCP6();
1406
1407 buildRelayMsg(dhcp6Parent, DHCP6.MsgType.RELAY_REPL.value(),
1408 INTERFACE_IP_V6.ipAddress().getIp6Address(),
1409 OUTER_RELAY_IP_V6,
1410 (byte) relayLevel, interfaceId,
1411 dhcp6Child);
1412
1413 dhcp6Child = dhcp6Parent;
1414 }
1415 if (dhcp6Parent != null) {
1416 dhcp6 = dhcp6Parent;
1417 }
1418
1419
1420 UDP udp = new UDP();
1421 udp.setPayload(dhcp6);
1422 udp.setSourcePort(UDP.DHCP_V6_SERVER_PORT);
1423 udp.setDestinationPort(UDP.DHCP_V6_CLIENT_PORT);
1424 IPv6 ipv6 = new IPv6();
1425 ipv6.setPayload(udp);
1426 ipv6.setNextHeader(IPv6.PROTOCOL_UDP);
1427 ipv6.setDestinationAddress(IP_FOR_CLIENT_V6.toOctets());
1428 ipv6.setSourceAddress(SERVER_IP_V6.toOctets());
1429 Ethernet eth = new Ethernet();
1430 if (relayLevel > 0) {
1431 eth.setEtherType(Ethernet.TYPE_IPV6)
1432 .setVlanID(SERVER_VLAN.toShort())
1433 .setSourceMACAddress(SERVER_MAC)
1434 .setDestinationMACAddress(OUTER_RELAY_MAC)
1435 .setPayload(ipv6);
1436 } else {
1437 eth.setEtherType(Ethernet.TYPE_IPV6)
1438 .setVlanID(SERVER_VLAN.toShort())
1439 .setSourceMACAddress(SERVER_MAC)
1440 .setDestinationMACAddress(CLIENT_MAC)
1441 .setPayload(ipv6);
1442 }
1443
1444 this.inPacket = new DefaultInboundPacket(SERVER_CONNECT_POINT, eth,
1445 ByteBuffer.wrap(eth.serialize()));
1446
1447 }
1448
1449 @Override
1450 public InboundPacket inPacket() {
1451 return this.inPacket;
1452 }
1453 }
1454
Yi Tseng7a38f9a2017-06-09 14:36:40 -07001455}