blob: 018c45002afc8d2ed89c20737e2fd26b365f284d [file] [log] [blame]
Yi Tseng7a38f9a2017-06-09 14:36:40 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Yi Tseng7a38f9a2017-06-09 14:36:40 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.dhcprelay;
17
Yi Tseng51f1be92017-09-01 17:24:57 -070018import com.fasterxml.jackson.databind.JsonNode;
19import com.fasterxml.jackson.databind.ObjectMapper;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070020import com.google.common.collect.ImmutableList;
21import com.google.common.collect.ImmutableSet;
22import com.google.common.collect.Lists;
23import com.google.common.collect.Maps;
24import com.google.common.collect.Sets;
Yi Tseng525ff402017-10-23 19:39:39 -070025import com.google.common.collect.Streams;
Yi Tseng51f1be92017-09-01 17:24:57 -070026import com.google.common.io.Resources;
Yi Tseng440e2b72017-08-24 14:47:34 -070027import org.apache.commons.io.Charsets;
Yi Tseng25bfe372017-11-03 16:27:32 -070028import org.apache.commons.lang3.tuple.Pair;
Yi Tseng51f1be92017-09-01 17:24:57 -070029import org.easymock.Capture;
30import org.easymock.CaptureType;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070031import org.easymock.EasyMock;
32import org.junit.After;
33import org.junit.Before;
34import org.junit.Test;
35import org.onlab.packet.ARP;
36import org.onlab.packet.DHCP;
Yi Tseng3df7f9d2017-08-17 13:08:31 -070037import org.onlab.packet.DeserializationException;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070038import org.onlab.packet.Ethernet;
39import org.onlab.packet.IPv4;
40import org.onlab.packet.Ip4Address;
Kalhee Kim45fede42017-09-05 19:05:06 +000041import org.onlab.packet.Ip6Address;
42import org.onlab.packet.IpPrefix;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070043import org.onlab.packet.IpAddress;
44import org.onlab.packet.MacAddress;
45import org.onlab.packet.UDP;
46import org.onlab.packet.VlanId;
47import org.onlab.packet.dhcp.CircuitId;
48import org.onlab.packet.dhcp.DhcpOption;
49import org.onlab.packet.dhcp.DhcpRelayAgentOption;
Kalhee Kim45fede42017-09-05 19:05:06 +000050import org.onlab.packet.dhcp.Dhcp6InterfaceIdOption;
51import org.onlab.packet.dhcp.Dhcp6RelayOption;
52import org.onlab.packet.dhcp.Dhcp6IaNaOption;
53import org.onlab.packet.dhcp.Dhcp6IaPdOption;
54import org.onlab.packet.dhcp.Dhcp6IaAddressOption;
55import org.onlab.packet.dhcp.Dhcp6IaPrefixOption;
56import org.onlab.packet.dhcp.Dhcp6Option;
Kalhee Kim495c9b22017-11-07 16:32:09 +000057import org.onlab.packet.dhcp.Dhcp6ClientIdOption;
58import org.onlab.packet.dhcp.Dhcp6Duid;
Kalhee Kim45fede42017-09-05 19:05:06 +000059import org.onosproject.net.ConnectPoint;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070060import org.onosproject.TestApplicationId;
61import org.onosproject.cfg.ComponentConfigService;
62import org.onosproject.core.ApplicationId;
63import org.onosproject.core.CoreService;
Yi Tseng483ac6f2017-08-02 15:03:31 -070064import org.onosproject.dhcprelay.config.DefaultDhcpRelayConfig;
65import org.onosproject.dhcprelay.config.DhcpServerConfig;
Yi Tseng51f1be92017-09-01 17:24:57 -070066import org.onosproject.dhcprelay.config.IgnoreDhcpConfig;
Yi Tseng483ac6f2017-08-02 15:03:31 -070067import org.onosproject.dhcprelay.config.IndirectDhcpRelayConfig;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070068import org.onosproject.dhcprelay.store.DhcpRecord;
69import org.onosproject.dhcprelay.store.DhcpRelayStore;
70import org.onosproject.dhcprelay.store.DhcpRelayStoreEvent;
Yi Tseng127ffe52017-09-12 15:55:17 -070071import org.onosproject.net.Device;
Yi Tseng51f1be92017-09-01 17:24:57 -070072import org.onosproject.net.DeviceId;
Yi Tseng127ffe52017-09-12 15:55:17 -070073import org.onosproject.net.behaviour.Pipeliner;
74import org.onosproject.net.device.DeviceEvent;
75import org.onosproject.net.device.DeviceService;
Yi Tseng51f1be92017-09-01 17:24:57 -070076import org.onosproject.net.flow.DefaultTrafficSelector;
77import org.onosproject.net.flow.DefaultTrafficTreatment;
78import org.onosproject.net.flow.TrafficSelector;
Yi Tseng51f1be92017-09-01 17:24:57 -070079import org.onosproject.net.flowobjective.FlowObjectiveService;
80import org.onosproject.net.flowobjective.ForwardingObjective;
81import org.onosproject.net.flowobjective.Objective;
Yi Tsengaa417a62017-09-08 17:22:51 -070082import org.onosproject.net.host.HostProviderService;
Ray Milkeyfacf2862017-08-03 11:58:29 -070083import org.onosproject.net.intf.Interface;
84import org.onosproject.net.intf.InterfaceServiceAdapter;
Yi Tseng51f1be92017-09-01 17:24:57 -070085import org.onosproject.net.packet.PacketPriority;
Ray Milkey69ec8712017-08-08 13:00:43 -070086import org.onosproject.routeservice.Route;
87import org.onosproject.routeservice.RouteStoreAdapter;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070088import org.onosproject.net.DefaultHost;
89import org.onosproject.net.Host;
90import org.onosproject.net.HostId;
91import org.onosproject.net.HostLocation;
92import org.onosproject.net.config.NetworkConfigRegistry;
93import org.onosproject.net.host.HostDescription;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070094import org.onosproject.net.host.HostService;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070095import org.onosproject.net.host.InterfaceIpAddress;
96import org.onosproject.net.packet.DefaultInboundPacket;
97import org.onosproject.net.packet.InboundPacket;
98import org.onosproject.net.packet.OutboundPacket;
99import org.onosproject.net.packet.PacketContext;
100import org.onosproject.net.packet.PacketContextAdapter;
101import org.onosproject.net.packet.PacketProcessor;
102import org.onosproject.net.packet.PacketServiceAdapter;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700103import org.onosproject.store.StoreDelegate;
Kalhee Kimba366062017-11-07 16:32:09 +0000104
105
106
107
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700108import org.osgi.service.component.ComponentContext;
Kalhee Kim45fede42017-09-05 19:05:06 +0000109import org.onlab.packet.DHCP6;
110import org.onlab.packet.IPv6;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700111
Yi Tseng127ffe52017-09-12 15:55:17 -0700112import java.io.IOException;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700113import java.nio.ByteBuffer;
114import java.util.Collection;
115import java.util.Dictionary;
116import java.util.List;
Kalhee Kim45fede42017-09-05 19:05:06 +0000117import java.util.ArrayList;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700118import java.util.Map;
119import java.util.Optional;
120import java.util.Set;
121import java.util.stream.Collectors;
122
123import static org.easymock.EasyMock.*;
124import static org.junit.Assert.*;
Yi Tseng51f1be92017-09-01 17:24:57 -0700125import static org.onosproject.dhcprelay.DhcpRelayManager.DHCP_RELAY_APP;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700126
127public class DhcpRelayManagerTest {
Kalhee Kima0b8f652017-10-18 22:00:30 +0000128 private static final short VLAN_LEN = 2;
129 private static final short SEPARATOR_LEN = 1;
Yi Tseng51f1be92017-09-01 17:24:57 -0700130 private static final String CONFIG_FILE_PATH = "dhcp-relay.json";
131 private static final DeviceId DEV_1_ID = DeviceId.deviceId("of:0000000000000001");
132 private static final DeviceId DEV_2_ID = DeviceId.deviceId("of:0000000000000002");
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700133 // Ip address for interfaces
134 private static final InterfaceIpAddress INTERFACE_IP = InterfaceIpAddress.valueOf("10.0.3.254/32");
Kalhee Kim45fede42017-09-05 19:05:06 +0000135 private static final InterfaceIpAddress INTERFACE_IP_V6 = InterfaceIpAddress.valueOf("2001:db8:1::254/128");
136 private static final List<InterfaceIpAddress> INTERFACE_IPS = ImmutableList.of(INTERFACE_IP, INTERFACE_IP_V6);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700137
138 // DHCP client (will send without option 82)
139 private static final Ip4Address IP_FOR_CLIENT = Ip4Address.valueOf("10.0.0.1");
Kalhee Kim45fede42017-09-05 19:05:06 +0000140 private static final Ip6Address IP_FOR_CLIENT_V6 = Ip6Address.valueOf("2001:db8:1::110");
141 private static final IpPrefix PREFIX_FOR_CLIENT_V6 = IpPrefix.valueOf("2001:db8:10::/56");
142 private static final IpPrefix PREFIX_FOR_ZERO = IpPrefix.valueOf("::/0");
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700143 private static final MacAddress CLIENT_MAC = MacAddress.valueOf("00:00:00:00:00:01");
144 private static final VlanId CLIENT_VLAN = VlanId.vlanId("100");
145 private static final ConnectPoint CLIENT_CP = ConnectPoint.deviceConnectPoint("of:0000000000000001/1");
146 private static final MacAddress CLIENT_IFACE_MAC = MacAddress.valueOf("00:00:00:00:11:01");
Yi Tsengaa417a62017-09-08 17:22:51 -0700147 private static final HostLocation CLIENT_LOCATION = new HostLocation(CLIENT_CP, 0);
148 private static final HostId CLIENT_HOST_ID = HostId.hostId(CLIENT_MAC, CLIENT_VLAN);
149 private static final Ip6Address CLIENT_LL_IP_V6 = Ip6Address.valueOf("fe80::200:00ff:fe00:0001");
Charles Chand988c282017-09-12 17:09:32 -0700150 private static final Host EXISTS_HOST = new DefaultHost(Dhcp4HandlerImpl.PROVIDER_ID,
Yi Tsengaa417a62017-09-08 17:22:51 -0700151 CLIENT_HOST_ID, CLIENT_MAC, CLIENT_VLAN,
152 CLIENT_LOCATION, ImmutableSet.of(CLIENT_LL_IP_V6));
Yi Tseng4025a102017-09-30 11:35:42 +0800153 private static final Interface CLIENT_INTERFACE = createInterface("C1",
154 CLIENT_CP,
155 INTERFACE_IPS,
156 CLIENT_IFACE_MAC,
157 CLIENT_VLAN,
158 null);
159
160
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700161
Yi Tsengaa417a62017-09-08 17:22:51 -0700162 // Dual homing test
163 private static final ConnectPoint CLIENT_DH_CP = ConnectPoint.deviceConnectPoint("of:0000000000000001/3");
164 private static final HostLocation CLIENT_DH_LOCATION = new HostLocation(CLIENT_DH_CP, 0);
Yi Tseng4025a102017-09-30 11:35:42 +0800165 private static final Interface CLIENT_DH_INTERFACE = createInterface("C1-DH",
166 CLIENT_DH_CP,
167 INTERFACE_IPS,
168 CLIENT_IFACE_MAC,
169 CLIENT_VLAN,
170 null);
Yi Tsengaa417a62017-09-08 17:22:51 -0700171
172
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700173 // DHCP client 2 (will send with option 82, so the vlan should equals to vlan from server)
174 private static final MacAddress CLIENT2_MAC = MacAddress.valueOf("00:00:00:00:00:01");
175 private static final VlanId CLIENT2_VLAN = VlanId.NONE;
Yi Tseng4025a102017-09-30 11:35:42 +0800176 private static final VlanId CLIENT2_VLAN_NATIVE = VlanId.vlanId("20");
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700177 private static final ConnectPoint CLIENT2_CP = ConnectPoint.deviceConnectPoint("of:0000000000000001/2");
178 private static final MacAddress CLIENT2_IFACE_MAC = MacAddress.valueOf("00:00:00:00:11:01");
Yi Tseng4025a102017-09-30 11:35:42 +0800179 private static final Interface CLIENT2_INTERFACE = createInterface("C2",
180 CLIENT2_CP,
181 INTERFACE_IPS,
182 CLIENT2_IFACE_MAC,
183 CLIENT2_VLAN,
184 CLIENT2_VLAN_NATIVE);
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000185 private static final VlanId CLIENT_BOGUS_VLAN = VlanId.vlanId("108");
186
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700187 // Outer relay information
Kalhee Kim121ba922017-11-01 17:56:44 +0000188 private static final Ip4Address OUTER_RELAY_IP = Ip4Address.valueOf("10.0.6.253");
Kalhee Kim45fede42017-09-05 19:05:06 +0000189 private static final Ip6Address OUTER_RELAY_IP_V6 = Ip6Address.valueOf("2001:db8:1::4");
Kalhee Kim121ba922017-11-01 17:56:44 +0000190 private static final Ip6Address OUTER_RELAY_LL_IP_V6 = Ip6Address.valueOf("fe80::200:0102:0304:0501");
191 private static final Set<IpAddress> OUTER_RELAY_IPS = ImmutableSet.of(OUTER_RELAY_IP,
192 OUTER_RELAY_IP_V6,
193 OUTER_RELAY_LL_IP_V6);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700194 private static final MacAddress OUTER_RELAY_MAC = MacAddress.valueOf("00:01:02:03:04:05");
195 private static final VlanId OUTER_RELAY_VLAN = VlanId.NONE;
196 private static final ConnectPoint OUTER_RELAY_CP = ConnectPoint.deviceConnectPoint("of:0000000000000001/2");
197 private static final HostLocation OUTER_REPLAY_HL = new HostLocation(OUTER_RELAY_CP, 0);
198 private static final HostId OUTER_RELAY_HOST_ID = HostId.hostId(OUTER_RELAY_MAC, OUTER_RELAY_VLAN);
Charles Chand988c282017-09-12 17:09:32 -0700199 private static final Host OUTER_RELAY_HOST = new DefaultHost(Dhcp4HandlerImpl.PROVIDER_ID,
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700200 OUTER_RELAY_HOST_ID,
201 OUTER_RELAY_MAC,
202 OUTER_RELAY_VLAN,
203 OUTER_REPLAY_HL,
204 OUTER_RELAY_IPS);
205
206 // DHCP Server
207 private static final MacAddress SERVER_MAC = MacAddress.valueOf("00:00:00:00:00:01");
208 private static final VlanId SERVER_VLAN = VlanId.NONE;
Yi Tseng4025a102017-09-30 11:35:42 +0800209 private static final VlanId SERVER_VLAN_NATIVE = VlanId.vlanId("10");
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700210 private static final ConnectPoint SERVER_CONNECT_POINT =
211 ConnectPoint.deviceConnectPoint("of:0000000000000001/5");
212 private static final HostLocation SERVER_LOCATION =
213 new HostLocation(SERVER_CONNECT_POINT, 0);
Kalhee Kim45fede42017-09-05 19:05:06 +0000214 private static final Ip4Address GATEWAY_IP = Ip4Address.valueOf("10.0.5.253");
215 private static final Ip6Address GATEWAY_IP_V6 = Ip6Address.valueOf("2000::105:253");
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700216 private static final Ip4Address SERVER_IP = Ip4Address.valueOf("10.0.3.253");
Kalhee Kim45fede42017-09-05 19:05:06 +0000217 private static final Ip6Address SERVER_IP_V6 = Ip6Address.valueOf("2000::103:253");
218 private static final Ip6Address SERVER_IP_V6_MCAST = Ip6Address.valueOf("ff02::1:2");
219 private static final Set<IpAddress> DHCP_SERVER_IPS = ImmutableSet.of(SERVER_IP, SERVER_IP_V6);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700220 private static final HostId SERVER_HOST_ID = HostId.hostId(SERVER_MAC, SERVER_VLAN);
Charles Chand988c282017-09-12 17:09:32 -0700221 private static final Host SERVER_HOST = new DefaultHost(Dhcp4HandlerImpl.PROVIDER_ID,
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700222 SERVER_HOST_ID,
223 SERVER_MAC,
224 SERVER_VLAN,
225 SERVER_LOCATION,
226 DHCP_SERVER_IPS);
227 private static final MacAddress SERVER_IFACE_MAC = MacAddress.valueOf("00:00:00:00:00:01");
Yi Tseng4025a102017-09-30 11:35:42 +0800228 private static final Interface SERVER_INTERFACE = createInterface("SERVER",
229 SERVER_CONNECT_POINT,
230 INTERFACE_IPS,
231 SERVER_IFACE_MAC,
232 SERVER_VLAN,
233 SERVER_VLAN_NATIVE);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700234
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700235 // Relay agent config
236 private static final Ip4Address RELAY_AGENT_IP = Ip4Address.valueOf("10.0.4.254");
237
Yi Tseng525ff402017-10-23 19:39:39 -0700238 private static final List<TrafficSelector> DHCP_SELECTORS = buildClientDhcpSelectors();
239
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700240 // Components
241 private static final ApplicationId APP_ID = TestApplicationId.create(DhcpRelayManager.DHCP_RELAY_APP);
Yi Tseng483ac6f2017-08-02 15:03:31 -0700242 private static final DefaultDhcpRelayConfig CONFIG = new MockDefaultDhcpRelayConfig();
Kalhee Kim45fede42017-09-05 19:05:06 +0000243 private static final IndirectDhcpRelayConfig CONFIG_INDIRECT = new MockIndirectDhcpRelayConfig();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700244 private static final Set<Interface> INTERFACES = ImmutableSet.of(
245 CLIENT_INTERFACE,
246 CLIENT2_INTERFACE,
Yi Tsengaa417a62017-09-08 17:22:51 -0700247 SERVER_INTERFACE,
248 CLIENT_DH_INTERFACE
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700249 );
Yi Tseng440e2b72017-08-24 14:47:34 -0700250 private static final String NON_ONOS_CID = "Non-ONOS circuit ID";
Yi Tseng51f1be92017-09-01 17:24:57 -0700251 private static final VlanId IGNORED_VLAN = VlanId.vlanId("100");
252 private static final int IGNORE_CONTROL_PRIORITY = PacketPriority.CONTROL.priorityValue() + 1000;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700253
254 private DhcpRelayManager manager;
255 private MockPacketService packetService;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700256 private MockRouteStore mockRouteStore;
257 private MockDhcpRelayStore mockDhcpRelayStore;
Yi Tsengaa417a62017-09-08 17:22:51 -0700258 private HostProviderService mockHostProviderService;
Yi Tseng525ff402017-10-23 19:39:39 -0700259 private FlowObjectiveService flowObjectiveService;
260 private DeviceService deviceService;
261 private Dhcp4HandlerImpl v4Handler;
262 private Dhcp6HandlerImpl v6Handler;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700263
Yi Tseng4025a102017-09-30 11:35:42 +0800264 private static Interface createInterface(String name, ConnectPoint connectPoint,
265 List<InterfaceIpAddress> interfaceIps,
266 MacAddress macAddress,
267 VlanId vlanId,
268 VlanId vlanNative) {
269
270 if (vlanId.equals(VlanId.NONE)) {
271 return new Interface(name, connectPoint, interfaceIps, macAddress, vlanId,
272 null, null, vlanNative);
273 } else {
274 return new Interface(name, connectPoint, interfaceIps, macAddress, vlanId,
275 null, ImmutableSet.of(vlanId), null);
276 }
277 }
278
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700279 @Before
280 public void setup() {
281 manager = new DhcpRelayManager();
282 manager.cfgService = createNiceMock(NetworkConfigRegistry.class);
283
Yi Tseng483ac6f2017-08-02 15:03:31 -0700284 expect(manager.cfgService.getConfig(APP_ID, DefaultDhcpRelayConfig.class))
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700285 .andReturn(CONFIG)
286 .anyTimes();
287
Yi Tseng483ac6f2017-08-02 15:03:31 -0700288 expect(manager.cfgService.getConfig(APP_ID, IndirectDhcpRelayConfig.class))
Kalhee Kim45fede42017-09-05 19:05:06 +0000289 .andReturn(CONFIG_INDIRECT)
Yi Tseng483ac6f2017-08-02 15:03:31 -0700290 .anyTimes();
291
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700292 manager.coreService = createNiceMock(CoreService.class);
293 expect(manager.coreService.registerApplication(anyString()))
294 .andReturn(APP_ID).anyTimes();
295
296 manager.hostService = createNiceMock(HostService.class);
Kalhee Kim121ba922017-11-01 17:56:44 +0000297
298 expect(manager.hostService.getHostsByIp(OUTER_RELAY_IP_V6))
299 .andReturn(ImmutableSet.of(OUTER_RELAY_HOST)).anyTimes();
300 expect(manager.hostService.getHostsByIp(SERVER_IP))
301 .andReturn(ImmutableSet.of(SERVER_HOST)).anyTimes();
302 expect(manager.hostService.getHostsByIp(SERVER_IP_V6))
303 .andReturn(ImmutableSet.of(SERVER_HOST)).anyTimes();
304 expect(manager.hostService.getHostsByIp(GATEWAY_IP))
305 .andReturn(ImmutableSet.of(SERVER_HOST)).anyTimes();
306 expect(manager.hostService.getHostsByIp(GATEWAY_IP_V6))
307 .andReturn(ImmutableSet.of(SERVER_HOST)).anyTimes();
308 expect(manager.hostService.getHostsByIp(CLIENT_LL_IP_V6))
309 .andReturn(ImmutableSet.of(EXISTS_HOST)).anyTimes();
310
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700311 expect(manager.hostService.getHost(OUTER_RELAY_HOST_ID)).andReturn(OUTER_RELAY_HOST).anyTimes();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700312
313 packetService = new MockPacketService();
314 manager.packetService = packetService;
315 manager.compCfgService = createNiceMock(ComponentConfigService.class);
Yi Tseng525ff402017-10-23 19:39:39 -0700316 deviceService = createNiceMock(DeviceService.class);
Yi Tseng127ffe52017-09-12 15:55:17 -0700317
318 Device device = createNiceMock(Device.class);
319 expect(device.is(Pipeliner.class)).andReturn(true).anyTimes();
320
Yi Tseng525ff402017-10-23 19:39:39 -0700321 expect(deviceService.getDevice(DEV_1_ID)).andReturn(device).anyTimes();
322 expect(deviceService.getDevice(DEV_2_ID)).andReturn(device).anyTimes();
323 replay(deviceService, device);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700324
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700325 mockRouteStore = new MockRouteStore();
326 mockDhcpRelayStore = new MockDhcpRelayStore();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700327 manager.dhcpRelayStore = mockDhcpRelayStore;
Yi Tseng525ff402017-10-23 19:39:39 -0700328 manager.deviceService = deviceService;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700329
Kalhee Kimba366062017-11-07 16:32:09 +0000330
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700331 manager.interfaceService = new MockInterfaceService();
Yi Tseng525ff402017-10-23 19:39:39 -0700332 flowObjectiveService = EasyMock.niceMock(FlowObjectiveService.class);
Yi Tsengaa417a62017-09-08 17:22:51 -0700333 mockHostProviderService = createNiceMock(HostProviderService.class);
Yi Tseng525ff402017-10-23 19:39:39 -0700334 v4Handler = new Dhcp4HandlerImpl();
Yi Tsengaa417a62017-09-08 17:22:51 -0700335 v4Handler.providerService = mockHostProviderService;
Yi Tseng51301292017-07-28 13:02:59 -0700336 v4Handler.dhcpRelayStore = mockDhcpRelayStore;
337 v4Handler.hostService = manager.hostService;
Yi Tseng51301292017-07-28 13:02:59 -0700338 v4Handler.interfaceService = manager.interfaceService;
339 v4Handler.packetService = manager.packetService;
340 v4Handler.routeStore = mockRouteStore;
Yi Tseng525ff402017-10-23 19:39:39 -0700341 v4Handler.coreService = createNiceMock(CoreService.class);
342 v4Handler.flowObjectiveService = flowObjectiveService;
343 v4Handler.appId = TestApplicationId.create(Dhcp4HandlerImpl.DHCP_V4_RELAY_APP);
344 v4Handler.deviceService = deviceService;
Yi Tseng51301292017-07-28 13:02:59 -0700345 manager.v4Handler = v4Handler;
346
Yi Tseng525ff402017-10-23 19:39:39 -0700347 v6Handler = new Dhcp6HandlerImpl();
Kalhee Kim45fede42017-09-05 19:05:06 +0000348 v6Handler.dhcpRelayStore = mockDhcpRelayStore;
349 v6Handler.hostService = manager.hostService;
Kalhee Kim45fede42017-09-05 19:05:06 +0000350 v6Handler.interfaceService = manager.interfaceService;
351 v6Handler.packetService = manager.packetService;
352 v6Handler.routeStore = mockRouteStore;
Yi Tsengaa417a62017-09-08 17:22:51 -0700353 v6Handler.providerService = mockHostProviderService;
Yi Tseng525ff402017-10-23 19:39:39 -0700354 v6Handler.coreService = createNiceMock(CoreService.class);
355 v6Handler.flowObjectiveService = flowObjectiveService;
356 v6Handler.appId = TestApplicationId.create(Dhcp6HandlerImpl.DHCP_V6_RELAY_APP);
357 v6Handler.deviceService = deviceService;
Yi Tseng483ac6f2017-08-02 15:03:31 -0700358 manager.v6Handler = v6Handler;
359
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700360 // properties
361 Dictionary<String, Object> dictionary = createNiceMock(Dictionary.class);
362 expect(dictionary.get("arpEnabled")).andReturn(true).anyTimes();
Kalhee Kim495c9b22017-11-07 16:32:09 +0000363 expect(dictionary.get("dhcpPollInterval")).andReturn(120).anyTimes();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700364 ComponentContext context = createNiceMock(ComponentContext.class);
365 expect(context.getProperties()).andReturn(dictionary).anyTimes();
366
Yi Tseng4025a102017-09-30 11:35:42 +0800367 replay(manager.cfgService, manager.coreService, manager.hostService,
368 manager.compCfgService, dictionary, context);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700369 manager.activate(context);
370 }
371
372 @After
373 public void tearDown() {
374 manager.deactivate();
375 }
376
377 /**
378 * Relay a DHCP packet without option 82.
379 * Should add new host to host store after dhcp ack.
380 */
381 @Test
382 public void relayDhcpWithoutAgentInfo() {
Yi Tsengaa417a62017-09-08 17:22:51 -0700383 replay(mockHostProviderService);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700384 // send request
385 packetService.processPacket(new TestDhcpRequestPacketContext(CLIENT_MAC,
386 CLIENT_VLAN,
387 CLIENT_CP,
388 INTERFACE_IP.ipAddress().getIp4Address(),
389 false));
Yi Tsengaa417a62017-09-08 17:22:51 -0700390 // won't trigger the host provider service
391 verify(mockHostProviderService);
392 reset(mockHostProviderService);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700393
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700394 assertEquals(0, mockRouteStore.routes.size());
395
Yi Tsengaa417a62017-09-08 17:22:51 -0700396 HostId expectHostId = HostId.hostId(CLIENT_MAC, CLIENT_VLAN);
397 Capture<HostDescription> capturedHostDesc = newCapture();
398 mockHostProviderService.hostDetected(eq(expectHostId), capture(capturedHostDesc), eq(false));
399 replay(mockHostProviderService);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700400 // send ack
401 packetService.processPacket(new TestDhcpAckPacketContext(CLIENT_CP, CLIENT_MAC,
402 CLIENT_VLAN, INTERFACE_IP.ipAddress().getIp4Address(),
403 false));
Yi Tsengaa417a62017-09-08 17:22:51 -0700404 verify(mockHostProviderService);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700405 assertEquals(0, mockRouteStore.routes.size());
406
Yi Tsengaa417a62017-09-08 17:22:51 -0700407 HostDescription host = capturedHostDesc.getValue();
408 assertEquals(false, host.configured());
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700409 assertEquals(CLIENT_CP.deviceId(), host.location().elementId());
410 assertEquals(CLIENT_CP.port(), host.location().port());
Yi Tsengaa417a62017-09-08 17:22:51 -0700411 assertEquals(1, host.ipAddress().size());
412 assertEquals(IP_FOR_CLIENT, host.ipAddress().iterator().next());
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700413 }
414
415 /**
416 * Relay a DHCP packet with option 82 (Indirectly connected host).
417 */
418 @Test
419 public void relayDhcpWithAgentInfo() {
Yi Tsengaa417a62017-09-08 17:22:51 -0700420 replay(mockHostProviderService);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700421 // Assume outer dhcp relay agent exists in store already
422 // send request
423 packetService.processPacket(new TestDhcpRequestPacketContext(CLIENT2_MAC,
424 CLIENT2_VLAN,
425 CLIENT2_CP,
426 INTERFACE_IP.ipAddress().getIp4Address(),
427 true));
Yi Tsengaa417a62017-09-08 17:22:51 -0700428 // No routes
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700429 assertEquals(0, mockRouteStore.routes.size());
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700430 // send ack
431 packetService.processPacket(new TestDhcpAckPacketContext(CLIENT2_CP,
432 CLIENT2_MAC,
433 CLIENT2_VLAN,
434 INTERFACE_IP.ipAddress().getIp4Address(),
435 true));
436
Yi Tsengaa417a62017-09-08 17:22:51 -0700437 // won't trigger the host provider service
438 verify(mockHostProviderService);
439 reset(mockHostProviderService);
440
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700441 assertEquals(1, mockRouteStore.routes.size());
442
443 Route route = mockRouteStore.routes.get(0);
444 assertEquals(OUTER_RELAY_IP, route.nextHop());
445 assertEquals(IP_FOR_CLIENT.toIpPrefix(), route.prefix());
446 assertEquals(Route.Source.STATIC, route.source());
447 }
448
449 @Test
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700450 public void testWithRelayAgentConfig() throws DeserializationException {
451 manager.v4Handler
452 .setDefaultDhcpServerConfigs(ImmutableList.of(new MockDhcpServerConfig(RELAY_AGENT_IP)));
Yi Tseng4f2a0462017-08-31 11:21:00 -0700453 manager.v4Handler
454 .setIndirectDhcpServerConfigs(ImmutableList.of(new MockDhcpServerConfig(RELAY_AGENT_IP)));
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700455 packetService.processPacket(new TestDhcpRequestPacketContext(CLIENT2_MAC,
456 CLIENT2_VLAN,
457 CLIENT2_CP,
458 INTERFACE_IP.ipAddress().getIp4Address(),
459 true));
460 OutboundPacket outPacket = packetService.emittedPacket;
461 byte[] outData = outPacket.data().array();
462 Ethernet eth = Ethernet.deserializer().deserialize(outData, 0, outData.length);
463 IPv4 ip = (IPv4) eth.getPayload();
464 UDP udp = (UDP) ip.getPayload();
465 DHCP dhcp = (DHCP) udp.getPayload();
466 assertEquals(RELAY_AGENT_IP.toInt(), dhcp.getGatewayIPAddress());
467 }
468
469 @Test
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700470 public void testArpRequest() throws Exception {
471 packetService.processPacket(new TestArpRequestPacketContext(CLIENT_INTERFACE));
Ray Milkeyc108a6b2017-08-23 15:23:50 -0700472 OutboundPacket outboundPacket = packetService.emittedPacket;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700473 byte[] outPacketData = outboundPacket.data().array();
474 Ethernet eth = Ethernet.deserializer().deserialize(outPacketData, 0, outPacketData.length);
475
476 assertEquals(eth.getEtherType(), Ethernet.TYPE_ARP);
477 ARP arp = (ARP) eth.getPayload();
478 assertArrayEquals(arp.getSenderHardwareAddress(), CLIENT_INTERFACE.mac().toBytes());
479 }
480
Yi Tseng51f1be92017-09-01 17:24:57 -0700481 /**
482 * Ignores specific vlans from specific devices if config.
483 *
484 * @throws Exception the exception from this test
485 */
486 @Test
487 public void testIgnoreVlan() throws Exception {
488 ObjectMapper om = new ObjectMapper();
489 JsonNode json = om.readTree(Resources.getResource(CONFIG_FILE_PATH));
490 IgnoreDhcpConfig config = new IgnoreDhcpConfig();
491 json = json.path("apps").path(DHCP_RELAY_APP).path(IgnoreDhcpConfig.KEY);
492 config.init(APP_ID, IgnoreDhcpConfig.KEY, json, om, null);
493
494 Capture<Objective> capturedFromDev1 = newCapture(CaptureType.ALL);
Yi Tseng525ff402017-10-23 19:39:39 -0700495 flowObjectiveService.apply(eq(DEV_1_ID), capture(capturedFromDev1));
Yi Tseng127ffe52017-09-12 15:55:17 -0700496 expectLastCall().times(DHCP_SELECTORS.size());
Yi Tseng51f1be92017-09-01 17:24:57 -0700497 Capture<Objective> capturedFromDev2 = newCapture(CaptureType.ALL);
Yi Tseng525ff402017-10-23 19:39:39 -0700498 flowObjectiveService.apply(eq(DEV_2_ID), capture(capturedFromDev2));
Yi Tseng127ffe52017-09-12 15:55:17 -0700499 expectLastCall().times(DHCP_SELECTORS.size());
Yi Tseng525ff402017-10-23 19:39:39 -0700500 replay(flowObjectiveService);
Yi Tseng51f1be92017-09-01 17:24:57 -0700501 manager.updateConfig(config);
Yi Tseng525ff402017-10-23 19:39:39 -0700502 verify(flowObjectiveService);
Yi Tseng51f1be92017-09-01 17:24:57 -0700503
504 List<Objective> objectivesFromDev1 = capturedFromDev1.getValues();
505 List<Objective> objectivesFromDev2 = capturedFromDev2.getValues();
506
507 assertTrue(objectivesFromDev1.containsAll(objectivesFromDev2));
508 assertTrue(objectivesFromDev2.containsAll(objectivesFromDev1));
Yi Tseng51f1be92017-09-01 17:24:57 -0700509
510 for (int index = 0; index < objectivesFromDev1.size(); index++) {
511 TrafficSelector selector =
Yi Tseng525ff402017-10-23 19:39:39 -0700512 DefaultTrafficSelector.builder(DHCP_SELECTORS.get(index))
Yi Tseng51f1be92017-09-01 17:24:57 -0700513 .matchVlanId(IGNORED_VLAN)
514 .build();
515 ForwardingObjective fwd = (ForwardingObjective) objectivesFromDev1.get(index);
516 assertEquals(selector, fwd.selector());
Yi Tsengdbabeed2017-11-29 10:49:20 -0800517 assertEquals(DefaultTrafficTreatment.emptyTreatment(), fwd.treatment());
Yi Tseng51f1be92017-09-01 17:24:57 -0700518 assertEquals(IGNORE_CONTROL_PRIORITY, fwd.priority());
519 assertEquals(ForwardingObjective.Flag.VERSATILE, fwd.flag());
520 assertEquals(Objective.Operation.ADD, fwd.op());
Yi Tseng127ffe52017-09-12 15:55:17 -0700521 fwd.context().ifPresent(ctx -> {
522 ctx.onSuccess(fwd);
523 });
Yi Tseng51f1be92017-09-01 17:24:57 -0700524 }
Yi Tseng127ffe52017-09-12 15:55:17 -0700525 objectivesFromDev2.forEach(obj -> obj.context().ifPresent(ctx -> ctx.onSuccess(obj)));
Yi Tseng525ff402017-10-23 19:39:39 -0700526 assertEquals(2, v4Handler.ignoredVlans.size());
527 assertEquals(2, v6Handler.ignoredVlans.size());
Yi Tseng51f1be92017-09-01 17:24:57 -0700528 }
529
530 /**
531 * "IgnoreVlan" policy should be removed when the config removed.
532 */
533 @Test
534 public void testRemoveIgnoreVlan() {
Yi Tseng525ff402017-10-23 19:39:39 -0700535 v4Handler.ignoredVlans.put(DEV_1_ID, IGNORED_VLAN);
536 v4Handler.ignoredVlans.put(DEV_2_ID, IGNORED_VLAN);
537 v6Handler.ignoredVlans.put(DEV_1_ID, IGNORED_VLAN);
538 v6Handler.ignoredVlans.put(DEV_2_ID, IGNORED_VLAN);
Yi Tseng51f1be92017-09-01 17:24:57 -0700539 IgnoreDhcpConfig config = new IgnoreDhcpConfig();
540
541 Capture<Objective> capturedFromDev1 = newCapture(CaptureType.ALL);
Yi Tseng525ff402017-10-23 19:39:39 -0700542 flowObjectiveService.apply(eq(DEV_1_ID), capture(capturedFromDev1));
Yi Tseng127ffe52017-09-12 15:55:17 -0700543 expectLastCall().times(DHCP_SELECTORS.size());
Yi Tseng51f1be92017-09-01 17:24:57 -0700544 Capture<Objective> capturedFromDev2 = newCapture(CaptureType.ALL);
Yi Tseng525ff402017-10-23 19:39:39 -0700545 flowObjectiveService.apply(eq(DEV_2_ID), capture(capturedFromDev2));
Yi Tseng127ffe52017-09-12 15:55:17 -0700546 expectLastCall().times(DHCP_SELECTORS.size());
Yi Tseng525ff402017-10-23 19:39:39 -0700547 replay(flowObjectiveService);
Yi Tseng51f1be92017-09-01 17:24:57 -0700548 manager.removeConfig(config);
Yi Tseng525ff402017-10-23 19:39:39 -0700549 verify(flowObjectiveService);
Yi Tseng51f1be92017-09-01 17:24:57 -0700550
551 List<Objective> objectivesFromDev1 = capturedFromDev1.getValues();
552 List<Objective> objectivesFromDev2 = capturedFromDev2.getValues();
553
554 assertTrue(objectivesFromDev1.containsAll(objectivesFromDev2));
555 assertTrue(objectivesFromDev2.containsAll(objectivesFromDev1));
Yi Tseng51f1be92017-09-01 17:24:57 -0700556
557 for (int index = 0; index < objectivesFromDev1.size(); index++) {
558 TrafficSelector selector =
Yi Tseng525ff402017-10-23 19:39:39 -0700559 DefaultTrafficSelector.builder(DHCP_SELECTORS.get(index))
Yi Tseng51f1be92017-09-01 17:24:57 -0700560 .matchVlanId(IGNORED_VLAN)
561 .build();
562 ForwardingObjective fwd = (ForwardingObjective) objectivesFromDev1.get(index);
563 assertEquals(selector, fwd.selector());
Yi Tsengdbabeed2017-11-29 10:49:20 -0800564 assertEquals(DefaultTrafficTreatment.emptyTreatment(), fwd.treatment());
Yi Tseng51f1be92017-09-01 17:24:57 -0700565 assertEquals(IGNORE_CONTROL_PRIORITY, fwd.priority());
566 assertEquals(ForwardingObjective.Flag.VERSATILE, fwd.flag());
567 assertEquals(Objective.Operation.REMOVE, fwd.op());
Yi Tseng127ffe52017-09-12 15:55:17 -0700568 fwd.context().ifPresent(ctx -> {
569 ctx.onSuccess(fwd);
570 });
Yi Tseng51f1be92017-09-01 17:24:57 -0700571 }
Yi Tseng127ffe52017-09-12 15:55:17 -0700572 objectivesFromDev2.forEach(obj -> obj.context().ifPresent(ctx -> ctx.onSuccess(obj)));
Yi Tseng525ff402017-10-23 19:39:39 -0700573 assertEquals(0, v4Handler.ignoredVlans.size());
574 assertEquals(0, v6Handler.ignoredVlans.size());
Yi Tseng51f1be92017-09-01 17:24:57 -0700575 }
576
Kalhee Kim45fede42017-09-05 19:05:06 +0000577 /**
Yi Tseng127ffe52017-09-12 15:55:17 -0700578 * Should ignore ignore rules installation when device not available.
579 */
580 @Test
581 public void testIgnoreUnknownDevice() throws IOException {
582 reset(manager.deviceService);
583 Device device = createNiceMock(Device.class);
584 expect(device.is(Pipeliner.class)).andReturn(true).anyTimes();
585
586 expect(manager.deviceService.getDevice(DEV_1_ID)).andReturn(device).anyTimes();
587 expect(manager.deviceService.getDevice(DEV_2_ID)).andReturn(null).anyTimes();
588
589 ObjectMapper om = new ObjectMapper();
590 JsonNode json = om.readTree(Resources.getResource(CONFIG_FILE_PATH));
591 IgnoreDhcpConfig config = new IgnoreDhcpConfig();
592 json = json.path("apps").path(DHCP_RELAY_APP).path(IgnoreDhcpConfig.KEY);
593 config.init(APP_ID, IgnoreDhcpConfig.KEY, json, om, null);
594
595 Capture<Objective> capturedFromDev1 = newCapture(CaptureType.ALL);
Yi Tseng525ff402017-10-23 19:39:39 -0700596 flowObjectiveService.apply(eq(DEV_1_ID), capture(capturedFromDev1));
Yi Tseng127ffe52017-09-12 15:55:17 -0700597 expectLastCall().times(DHCP_SELECTORS.size());
Yi Tseng525ff402017-10-23 19:39:39 -0700598 replay(flowObjectiveService, manager.deviceService, device);
Yi Tseng127ffe52017-09-12 15:55:17 -0700599
600 manager.updateConfig(config);
601 capturedFromDev1.getValues().forEach(obj -> obj.context().ifPresent(ctx -> ctx.onSuccess(obj)));
602
Yi Tseng525ff402017-10-23 19:39:39 -0700603 assertEquals(1, v4Handler.ignoredVlans.size());
604 assertEquals(1, v6Handler.ignoredVlans.size());
Yi Tseng127ffe52017-09-12 15:55:17 -0700605 }
606
607 /**
608 * Should try install ignore rules when device comes up.
609 */
610 @Test
611 public void testInstallIgnoreRuleWhenDeviceComesUp() throws IOException {
612 ObjectMapper om = new ObjectMapper();
613 JsonNode json = om.readTree(Resources.getResource(CONFIG_FILE_PATH));
614 IgnoreDhcpConfig config = new IgnoreDhcpConfig();
615 json = json.path("apps").path(DHCP_RELAY_APP).path(IgnoreDhcpConfig.KEY);
616 config.init(APP_ID, IgnoreDhcpConfig.KEY, json, om, null);
617
Yi Tseng525ff402017-10-23 19:39:39 -0700618 reset(manager.cfgService, flowObjectiveService, manager.deviceService);
Yi Tseng127ffe52017-09-12 15:55:17 -0700619 expect(manager.cfgService.getConfig(APP_ID, IgnoreDhcpConfig.class))
620 .andReturn(config).anyTimes();
621
622 Device device = createNiceMock(Device.class);
623 expect(device.is(Pipeliner.class)).andReturn(true).anyTimes();
624 expect(device.id()).andReturn(DEV_1_ID).anyTimes();
625 expect(manager.deviceService.getDevice(DEV_1_ID)).andReturn(device).anyTimes();
626 DeviceEvent event = new DeviceEvent(DeviceEvent.Type.DEVICE_ADDED, device);
627 Capture<Objective> capturedFromDev1 = newCapture(CaptureType.ALL);
Yi Tseng525ff402017-10-23 19:39:39 -0700628 flowObjectiveService.apply(eq(DEV_1_ID), capture(capturedFromDev1));
Yi Tseng127ffe52017-09-12 15:55:17 -0700629 expectLastCall().times(DHCP_SELECTORS.size());
Yi Tseng525ff402017-10-23 19:39:39 -0700630 replay(manager.cfgService, flowObjectiveService, manager.deviceService, device);
Yi Tseng127ffe52017-09-12 15:55:17 -0700631 manager.deviceListener.event(event);
632 capturedFromDev1.getValues().forEach(obj -> obj.context().ifPresent(ctx -> ctx.onSuccess(obj)));
Yi Tseng525ff402017-10-23 19:39:39 -0700633 assertEquals(1, v4Handler.ignoredVlans.size());
634 assertEquals(1, v6Handler.ignoredVlans.size());
Yi Tseng127ffe52017-09-12 15:55:17 -0700635 }
636
637 /**
Kalhee Kim45fede42017-09-05 19:05:06 +0000638 * Relay a DHCP6 packet without relay option
639 * Note: Should add new host to host store after dhcp ack.
640 */
641 @Test
642 public void relayDhcp6WithoutAgentInfo() {
Yi Tsengaa417a62017-09-08 17:22:51 -0700643 replay(mockHostProviderService);
Kalhee Kim45fede42017-09-05 19:05:06 +0000644 // send request
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000645 packetService.processPacket(new TestDhcp6RequestPacketContext(DHCP6.MsgType.REQUEST.value(),
646 CLIENT_MAC,
647 CLIENT_VLAN,
Kalhee Kim45fede42017-09-05 19:05:06 +0000648 CLIENT_CP,
649 INTERFACE_IP_V6.ipAddress().getIp6Address(),
650 0));
651
Yi Tsengaa417a62017-09-08 17:22:51 -0700652 verify(mockHostProviderService);
653 reset(mockHostProviderService);
Kalhee Kim45fede42017-09-05 19:05:06 +0000654 assertEquals(0, mockRouteStore.routes.size());
655
Yi Tsengaa417a62017-09-08 17:22:51 -0700656 Capture<HostDescription> capturedHostDesc = newCapture();
657 mockHostProviderService.hostDetected(eq(HostId.hostId(CLIENT_MAC, CLIENT_VLAN)),
658 capture(capturedHostDesc), eq(false));
659 replay(mockHostProviderService);
Kalhee Kim45fede42017-09-05 19:05:06 +0000660 // send reply
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000661 packetService.processPacket(new TestDhcp6ReplyPacketContext(DHCP6.MsgType.REPLY.value(),
662 CLIENT_CP, CLIENT_MAC,
Kalhee Kim45fede42017-09-05 19:05:06 +0000663 CLIENT_VLAN,
664 INTERFACE_IP_V6.ipAddress().getIp6Address(),
Kalhee Kim121ba922017-11-01 17:56:44 +0000665 0, false, CLIENT_VLAN));
Yi Tsengaa417a62017-09-08 17:22:51 -0700666 verify(mockHostProviderService);
Kalhee Kim45fede42017-09-05 19:05:06 +0000667 assertEquals(0, mockRouteStore.routes.size());
668
Yi Tsengaa417a62017-09-08 17:22:51 -0700669 HostDescription host = capturedHostDesc.getValue();
Kalhee Kim45fede42017-09-05 19:05:06 +0000670 assertEquals(CLIENT_VLAN, host.vlan());
671 assertEquals(CLIENT_CP.deviceId(), host.location().elementId());
672 assertEquals(CLIENT_CP.port(), host.location().port());
Yi Tsengaa417a62017-09-08 17:22:51 -0700673 assertEquals(1, host.ipAddress().size());
674 assertEquals(IP_FOR_CLIENT_V6, host.ipAddress().iterator().next());
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000675
676 // send release
677 packetService.processPacket(new TestDhcp6RequestPacketContext(DHCP6.MsgType.RELEASE.value(),
678 CLIENT_MAC,
679 CLIENT_VLAN,
680 CLIENT_CP,
681 INTERFACE_IP_V6.ipAddress().getIp6Address(),
682 0));
683
684 assertEquals(null, manager.hostService.getHost(HostId.hostId(CLIENT_MAC, CLIENT_VLAN)));
Kalhee Kim45fede42017-09-05 19:05:06 +0000685 }
686
687 /**
688 * Relay a DHCP6 packet with Relay Message opion (Indirectly connected host).
689 */
690 @Test
691 public void relayDhcp6WithAgentInfo() {
Yi Tsengaa417a62017-09-08 17:22:51 -0700692 replay(mockHostProviderService);
Kalhee Kim45fede42017-09-05 19:05:06 +0000693 // Assume outer dhcp6 relay agent exists in store already
694 // send request
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000695 packetService.processPacket(new TestDhcp6RequestPacketContext(DHCP6.MsgType.REQUEST.value(),
696 CLIENT2_MAC,
697 CLIENT2_VLAN,
698 CLIENT2_CP,
699 OUTER_RELAY_IP_V6,
700 1));
701
702 assertEquals(0, mockRouteStore.routes.size());
703
704 // send reply
705 packetService.processPacket(new TestDhcp6ReplyPacketContext(DHCP6.MsgType.REPLY.value(), CLIENT2_CP,
706 CLIENT2_MAC,
707 CLIENT2_VLAN,
708 OUTER_RELAY_IP_V6,
Kalhee Kim121ba922017-11-01 17:56:44 +0000709 1, false, CLIENT2_VLAN));
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000710
711 // won't trigger the host provider service
712 verify(mockHostProviderService);
713 reset(mockHostProviderService);
714 assertEquals(2, mockRouteStore.routes.size()); // ipAddress and prefix
715
716 Route aRoute = mockRouteStore.routes.stream()
717 .filter(rt -> rt.prefix().contains(IP_FOR_CLIENT_V6))
718 .findFirst()
719 .orElse(null);
720 assertNotEquals(null, aRoute);
721
722 aRoute = mockRouteStore.routes.stream()
723 .filter(rt -> rt.prefix().contains(PREFIX_FOR_CLIENT_V6))
724 .findFirst()
725 .orElse(null);
726 assertNotEquals(null, aRoute);
727
728 // send release msg
729 packetService.processPacket(new TestDhcp6RequestPacketContext(DHCP6.MsgType.RELEASE.value(),
730 CLIENT2_MAC,
731 CLIENT2_VLAN,
732 CLIENT2_CP,
733 OUTER_RELAY_IP_V6,
734 1));
735
736 aRoute = mockRouteStore.routes.stream()
737 .filter(rt -> rt.prefix().contains(IP_FOR_CLIENT_V6))
738 .findFirst()
739 .orElse(null);
740 assertEquals(null, aRoute);
741
742 aRoute = mockRouteStore.routes.stream()
743 .filter(rt -> rt.prefix().contains(PREFIX_FOR_CLIENT_V6))
744 .findFirst()
745 .orElse(null);
746 assertEquals(null, aRoute);
747
748 assertEquals(0, mockRouteStore.routes.size());
749
750 }
751
752 /**
753 * Relay a DHCP6 packet with Relay Message opion (Indirectly connected host) and server responded
754 * with vlan differnt from client interface vlan.
755 */
756 @Test
757 public void relayDhcp6WithAgentInfoWrongVlan() {
758 replay(mockHostProviderService);
759 // Assume outer dhcp6 relay agent exists in store already
760 // send request
761 packetService.processPacket(new TestDhcp6RequestPacketContext(DHCP6.MsgType.REQUEST.value(),
762 CLIENT2_MAC,
Kalhee Kim45fede42017-09-05 19:05:06 +0000763 CLIENT2_VLAN,
764 CLIENT2_CP,
765 INTERFACE_IP_V6.ipAddress().getIp6Address(),
766 1));
767
Kalhee Kim45fede42017-09-05 19:05:06 +0000768 assertEquals(0, mockRouteStore.routes.size());
769
770 // send reply
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000771 packetService.processPacket(new TestDhcp6ReplyPacketContext(DHCP6.MsgType.REPLY.value(),
772 CLIENT2_CP,
Kalhee Kim45fede42017-09-05 19:05:06 +0000773 CLIENT2_MAC,
Kalhee Kim121ba922017-11-01 17:56:44 +0000774 CLIENT2_VLAN,
Kalhee Kim45fede42017-09-05 19:05:06 +0000775 INTERFACE_IP_V6.ipAddress().getIp6Address(),
Kalhee Kim121ba922017-11-01 17:56:44 +0000776 1, true,
777 CLIENT_BOGUS_VLAN // mismatch
778 ));
Kalhee Kim45fede42017-09-05 19:05:06 +0000779
Yi Tsengaa417a62017-09-08 17:22:51 -0700780 // won't trigger the host provider service
781 verify(mockHostProviderService);
782 reset(mockHostProviderService);
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000783 assertEquals(0, mockRouteStore.routes.size()); // ipAddress and prefix
Kalhee Kim45fede42017-09-05 19:05:06 +0000784
Kalhee Kim45fede42017-09-05 19:05:06 +0000785 }
Yi Tsengaa417a62017-09-08 17:22:51 -0700786
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000787
Yi Tsengaa417a62017-09-08 17:22:51 -0700788 @Test
789 public void testDhcp4DualHome() {
790 PacketContext packetContext =
791 new TestDhcpAckPacketContext(CLIENT_DH_CP, CLIENT_MAC, CLIENT_VLAN,
792 INTERFACE_IP.ipAddress().getIp4Address(),
793 false);
794 reset(manager.hostService);
795 expect(manager.hostService.getHost(CLIENT_HOST_ID)).andReturn(EXISTS_HOST).anyTimes();
796 Capture<HostDescription> capturedHostDesc = newCapture();
797 mockHostProviderService.hostDetected(eq(CLIENT_HOST_ID), capture(capturedHostDesc), eq(false));
798 replay(mockHostProviderService, manager.hostService);
799 packetService.processPacket(packetContext);
800 verify(mockHostProviderService);
801
802 HostDescription hostDesc = capturedHostDesc.getValue();
803 Set<HostLocation> hostLocations = hostDesc.locations();
804 assertEquals(2, hostLocations.size());
805 assertTrue(hostLocations.contains(CLIENT_LOCATION));
806 assertTrue(hostLocations.contains(CLIENT_DH_LOCATION));
807 }
808
809 @Test
810 public void testDhcp6DualHome() {
811 PacketContext packetContext =
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000812 new TestDhcp6ReplyPacketContext(DHCP6.MsgType.REPLY.value(),
813 CLIENT_DH_CP, CLIENT_MAC, CLIENT_VLAN,
Yi Tsengaa417a62017-09-08 17:22:51 -0700814 INTERFACE_IP_V6.ipAddress().getIp6Address(),
Kalhee Kim121ba922017-11-01 17:56:44 +0000815 0, false, CLIENT_VLAN);
Yi Tsengaa417a62017-09-08 17:22:51 -0700816 reset(manager.hostService);
817 expect(manager.hostService.getHostsByIp(CLIENT_LL_IP_V6)).andReturn(ImmutableSet.of(EXISTS_HOST)).anyTimes();
818
819 // FIXME: currently DHCPv6 has a bug, we can't get correct vlan of client......
820 // XXX: The vlan relied from DHCP6 handler might be wrong, do hack here
821 HostId hostId = HostId.hostId(CLIENT_MAC, VlanId.NONE);
822 expect(manager.hostService.getHost(hostId)).andReturn(EXISTS_HOST).anyTimes();
823
824 // XXX: sometimes this will work, sometimes not
825 expect(manager.hostService.getHost(CLIENT_HOST_ID)).andReturn(EXISTS_HOST).anyTimes();
826
827 Capture<HostDescription> capturedHostDesc = newCapture();
828
829 // XXX: also a hack here
830 mockHostProviderService.hostDetected(eq(hostId), capture(capturedHostDesc), eq(false));
831 expectLastCall().anyTimes();
832
833 mockHostProviderService.hostDetected(eq(CLIENT_HOST_ID), capture(capturedHostDesc), eq(false));
834 expectLastCall().anyTimes();
835 replay(mockHostProviderService, manager.hostService);
836 packetService.processPacket(packetContext);
837 verify(mockHostProviderService);
838
839 HostDescription hostDesc = capturedHostDesc.getValue();
840 Set<HostLocation> hostLocations = hostDesc.locations();
841 assertEquals(2, hostLocations.size());
842 assertTrue(hostLocations.contains(CLIENT_LOCATION));
843 assertTrue(hostLocations.contains(CLIENT_DH_LOCATION));
844 }
845
Yi Tseng483ac6f2017-08-02 15:03:31 -0700846 private static class MockDefaultDhcpRelayConfig extends DefaultDhcpRelayConfig {
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700847 @Override
848 public boolean isValid() {
849 return true;
850 }
851
852 @Override
Yi Tseng483ac6f2017-08-02 15:03:31 -0700853 public List<DhcpServerConfig> dhcpServerConfigs() {
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700854 return ImmutableList.of(new MockDhcpServerConfig(null));
Yi Tseng483ac6f2017-08-02 15:03:31 -0700855 }
856 }
857
Kalhee Kim45fede42017-09-05 19:05:06 +0000858 private static class MockIndirectDhcpRelayConfig extends IndirectDhcpRelayConfig {
859 @Override
860 public boolean isValid() {
861 return true;
862 }
863
864 @Override
865 public List<DhcpServerConfig> dhcpServerConfigs() {
866 return ImmutableList.of(new MockDhcpServerConfig(null));
867 }
868 }
869
Yi Tseng483ac6f2017-08-02 15:03:31 -0700870 private static class MockDhcpServerConfig extends DhcpServerConfig {
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700871 Ip4Address relayAgentIp;
872
873 /**
874 * Create mocked version DHCP server config.
875 *
876 * @param relayAgentIp the relay agent Ip config; null if we don't need it
877 */
878 public MockDhcpServerConfig(Ip4Address relayAgentIp) {
879 this.relayAgentIp = relayAgentIp;
Yi Tseng25bfe372017-11-03 16:27:32 -0700880 this.relayAgentIps.put(DEV_1_ID, Pair.of(relayAgentIp, null));
881 this.relayAgentIps.put(DEV_2_ID, Pair.of(relayAgentIp, null));
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700882 }
883
884 @Override
Yi Tseng25bfe372017-11-03 16:27:32 -0700885 public Optional<Ip4Address> getRelayAgentIp4(DeviceId deviceId) {
886 return Optional.ofNullable(this.relayAgentIps.get(deviceId).getLeft());
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700887 }
888
Yi Tseng483ac6f2017-08-02 15:03:31 -0700889 @Override
890 public Optional<ConnectPoint> getDhcpServerConnectPoint() {
891 return Optional.of(SERVER_CONNECT_POINT);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700892 }
893
Yi Tseng483ac6f2017-08-02 15:03:31 -0700894 @Override
895 public Optional<Ip4Address> getDhcpServerIp4() {
896 return Optional.of(SERVER_IP);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700897 }
Kalhee Kim45fede42017-09-05 19:05:06 +0000898
899 @Override
900 public Optional<Ip4Address> getDhcpGatewayIp4() {
901 return Optional.of(GATEWAY_IP);
902 }
903
904 @Override
905 public Optional<Ip6Address> getDhcpServerIp6() {
906 return Optional.of(SERVER_IP_V6);
907 }
908
909 @Override
910 public Optional<Ip6Address> getDhcpGatewayIp6() {
911 return Optional.of(GATEWAY_IP_V6);
912 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700913 }
914
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700915 private class MockRouteStore extends RouteStoreAdapter {
916 private List<Route> routes = Lists.newArrayList();
917
918 @Override
919 public void updateRoute(Route route) {
920 routes.add(route);
921 }
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000922
923 @Override
924 public void removeRoute(Route route) {
925 routes.remove(route);
926 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700927 }
928
929 private class MockInterfaceService extends InterfaceServiceAdapter {
930
931 @Override
932 public Set<Interface> getInterfaces() {
933 return INTERFACES;
934 }
935
936 @Override
937 public Set<Interface> getInterfacesByIp(IpAddress ip) {
938 return INTERFACES.stream()
939 .filter(iface -> {
940 return iface.ipAddressesList().stream()
941 .anyMatch(ifaceIp -> ifaceIp.ipAddress().equals(ip));
942 })
943 .collect(Collectors.toSet());
944 }
945
946 @Override
947 public Set<Interface> getInterfacesByPort(ConnectPoint port) {
948 return INTERFACES.stream()
949 .filter(iface -> iface.connectPoint().equals(port))
950 .collect(Collectors.toSet());
951 }
952 }
953
954 private class MockDhcpRelayStore implements DhcpRelayStore {
955 StoreDelegate<DhcpRelayStoreEvent> delegate;
956 private Map<HostId, DhcpRecord> records = Maps.newHashMap();
957
958 @Override
959 public void updateDhcpRecord(HostId hostId, DhcpRecord dhcpRecord) {
960 records.put(hostId, dhcpRecord);
961 DhcpRelayStoreEvent event = new DhcpRelayStoreEvent(DhcpRelayStoreEvent.Type.UPDATED,
962 dhcpRecord);
963 if (delegate != null) {
964 delegate.notify(event);
965 }
966 }
967
968 @Override
969 public Optional<DhcpRecord> getDhcpRecord(HostId hostId) {
970 return Optional.ofNullable(records.get(hostId));
971 }
972
973 @Override
974 public Collection<DhcpRecord> getDhcpRecords() {
975 return records.values();
976 }
977
978 @Override
979 public Optional<DhcpRecord> removeDhcpRecord(HostId hostId) {
980 DhcpRecord dhcpRecord = records.remove(hostId);
981 if (dhcpRecord != null) {
982 DhcpRelayStoreEvent event = new DhcpRelayStoreEvent(DhcpRelayStoreEvent.Type.REMOVED,
983 dhcpRecord);
984 if (delegate != null) {
985 delegate.notify(event);
986 }
987 }
988 return Optional.ofNullable(dhcpRecord);
989 }
990
991 @Override
992 public void setDelegate(StoreDelegate<DhcpRelayStoreEvent> delegate) {
993 this.delegate = delegate;
994 }
995
996 @Override
997 public void unsetDelegate(StoreDelegate<DhcpRelayStoreEvent> delegate) {
998 this.delegate = null;
999 }
1000
1001 @Override
1002 public boolean hasDelegate() {
1003 return this.delegate != null;
1004 }
1005 }
1006
1007 private class MockPacketService extends PacketServiceAdapter {
1008 Set<PacketProcessor> packetProcessors = Sets.newHashSet();
Ray Milkeyc108a6b2017-08-23 15:23:50 -07001009 OutboundPacket emittedPacket;
Yi Tseng7a38f9a2017-06-09 14:36:40 -07001010
1011 @Override
1012 public void addProcessor(PacketProcessor processor, int priority) {
1013 packetProcessors.add(processor);
1014 }
1015
1016 public void processPacket(PacketContext packetContext) {
1017 packetProcessors.forEach(p -> p.process(packetContext));
1018 }
1019
1020 @Override
1021 public void emit(OutboundPacket packet) {
Ray Milkeyc108a6b2017-08-23 15:23:50 -07001022 this.emittedPacket = packet;
Yi Tseng7a38f9a2017-06-09 14:36:40 -07001023 }
1024 }
1025
1026
1027
1028 /**
1029 * Generates DHCP REQUEST packet.
1030 */
1031 private class TestDhcpRequestPacketContext extends PacketContextAdapter {
1032
1033
1034 private InboundPacket inPacket;
1035
1036 public TestDhcpRequestPacketContext(MacAddress clientMac, VlanId vlanId,
1037 ConnectPoint clientCp,
1038 Ip4Address clientGwAddr,
1039 boolean withNonOnosRelayInfo) {
1040 super(0, null, null, false);
1041 byte[] dhcpMsgType = new byte[1];
1042 dhcpMsgType[0] = (byte) DHCP.MsgType.DHCPREQUEST.getValue();
1043
1044 DhcpOption dhcpOption = new DhcpOption();
1045 dhcpOption.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue());
1046 dhcpOption.setData(dhcpMsgType);
1047 dhcpOption.setLength((byte) 1);
1048 DhcpOption endOption = new DhcpOption();
1049 endOption.setCode(DHCP.DHCPOptionCode.OptionCode_END.getValue());
1050
1051 DHCP dhcp = new DHCP();
1052 dhcp.setHardwareType(DHCP.HWTYPE_ETHERNET);
1053 dhcp.setHardwareAddressLength((byte) 6);
1054 dhcp.setClientHardwareAddress(clientMac.toBytes());
1055 if (withNonOnosRelayInfo) {
1056 DhcpRelayAgentOption relayOption = new DhcpRelayAgentOption();
1057 DhcpOption circuitIdOption = new DhcpOption();
1058 CircuitId circuitId = new CircuitId("Custom option", VlanId.NONE);
1059 byte[] cid = circuitId.serialize();
1060 circuitIdOption.setCode(DhcpRelayAgentOption.RelayAgentInfoOptions.CIRCUIT_ID.getValue());
1061 circuitIdOption.setLength((byte) cid.length);
1062 circuitIdOption.setData(cid);
1063 relayOption.setCode(DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue());
1064 relayOption.addSubOption(circuitIdOption);
1065 dhcp.setOptions(ImmutableList.of(dhcpOption, relayOption, endOption));
1066 dhcp.setGatewayIPAddress(OUTER_RELAY_IP.getIp4Address().toInt());
1067 } else {
1068 dhcp.setOptions(ImmutableList.of(dhcpOption, endOption));
1069 }
1070
1071
1072 UDP udp = new UDP();
1073 udp.setPayload(dhcp);
1074 udp.setSourcePort(UDP.DHCP_CLIENT_PORT);
1075 udp.setDestinationPort(UDP.DHCP_SERVER_PORT);
1076
1077 IPv4 ipv4 = new IPv4();
1078 ipv4.setPayload(udp);
1079 ipv4.setDestinationAddress(SERVER_IP.toInt());
1080 ipv4.setSourceAddress(clientGwAddr.toInt());
1081
1082 Ethernet eth = new Ethernet();
1083 if (withNonOnosRelayInfo) {
1084 eth.setEtherType(Ethernet.TYPE_IPV4)
1085 .setVlanID(vlanId.toShort())
1086 .setSourceMACAddress(OUTER_RELAY_MAC)
1087 .setDestinationMACAddress(MacAddress.BROADCAST)
1088 .setPayload(ipv4);
1089 } else {
1090 eth.setEtherType(Ethernet.TYPE_IPV4)
1091 .setVlanID(vlanId.toShort())
1092 .setSourceMACAddress(clientMac)
1093 .setDestinationMACAddress(MacAddress.BROADCAST)
1094 .setPayload(ipv4);
1095 }
1096
1097 this.inPacket = new DefaultInboundPacket(clientCp, eth,
1098 ByteBuffer.wrap(eth.serialize()));
1099 }
1100
1101 @Override
1102 public InboundPacket inPacket() {
1103 return this.inPacket;
1104 }
1105 }
1106
1107 /**
1108 * Generates DHCP ACK packet.
1109 */
1110 private class TestDhcpAckPacketContext extends PacketContextAdapter {
1111 private InboundPacket inPacket;
1112
1113 public TestDhcpAckPacketContext(ConnectPoint clientCp, MacAddress clientMac,
1114 VlanId clientVlan, Ip4Address clientGwAddr,
1115 boolean withNonOnosRelayInfo) {
1116 super(0, null, null, false);
1117
1118 byte[] dhcpMsgType = new byte[1];
1119 dhcpMsgType[0] = (byte) DHCP.MsgType.DHCPACK.getValue();
1120
1121 DhcpOption dhcpOption = new DhcpOption();
1122 dhcpOption.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue());
1123 dhcpOption.setData(dhcpMsgType);
1124 dhcpOption.setLength((byte) 1);
1125
1126 DhcpOption endOption = new DhcpOption();
1127 endOption.setCode(DHCP.DHCPOptionCode.OptionCode_END.getValue());
1128
1129 DHCP dhcp = new DHCP();
1130 if (withNonOnosRelayInfo) {
1131 DhcpRelayAgentOption relayOption = new DhcpRelayAgentOption();
1132 DhcpOption circuitIdOption = new DhcpOption();
Yi Tseng440e2b72017-08-24 14:47:34 -07001133 String circuitId = NON_ONOS_CID;
1134 byte[] cid = circuitId.getBytes(Charsets.US_ASCII);
Yi Tseng7a38f9a2017-06-09 14:36:40 -07001135 circuitIdOption.setCode(DhcpRelayAgentOption.RelayAgentInfoOptions.CIRCUIT_ID.getValue());
1136 circuitIdOption.setLength((byte) cid.length);
1137 circuitIdOption.setData(cid);
1138 relayOption.setCode(DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue());
1139 relayOption.addSubOption(circuitIdOption);
1140 dhcp.setOptions(ImmutableList.of(dhcpOption, relayOption, endOption));
1141 dhcp.setGatewayIPAddress(OUTER_RELAY_IP.getIp4Address().toInt());
1142 } else {
1143 CircuitId cid = new CircuitId(clientCp.toString(), clientVlan);
1144 byte[] circuitId = cid.serialize();
1145 DhcpOption circuitIdSubOption = new DhcpOption();
1146 circuitIdSubOption.setCode(DhcpRelayAgentOption.RelayAgentInfoOptions.CIRCUIT_ID.getValue());
1147 circuitIdSubOption.setData(circuitId);
1148 circuitIdSubOption.setLength((byte) circuitId.length);
1149
1150 DhcpRelayAgentOption relayInfoOption = new DhcpRelayAgentOption();
1151 relayInfoOption.setCode(DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue());
1152 relayInfoOption.addSubOption(circuitIdSubOption);
1153 dhcp.setOptions(ImmutableList.of(dhcpOption, relayInfoOption, endOption));
1154 dhcp.setGatewayIPAddress(clientGwAddr.toInt());
1155 }
1156 dhcp.setHardwareType(DHCP.HWTYPE_ETHERNET);
1157 dhcp.setHardwareAddressLength((byte) 6);
1158 dhcp.setClientHardwareAddress(clientMac.toBytes());
1159 dhcp.setYourIPAddress(IP_FOR_CLIENT.toInt());
1160
1161 UDP udp = new UDP();
1162 udp.setPayload(dhcp);
1163 udp.setSourcePort(UDP.DHCP_SERVER_PORT);
1164 udp.setDestinationPort(UDP.DHCP_CLIENT_PORT);
1165 IPv4 ipv4 = new IPv4();
1166 ipv4.setPayload(udp);
1167 ipv4.setDestinationAddress(IP_FOR_CLIENT.toString());
1168 ipv4.setSourceAddress(SERVER_IP.toString());
1169 Ethernet eth = new Ethernet();
1170 if (withNonOnosRelayInfo) {
1171 eth.setEtherType(Ethernet.TYPE_IPV4)
1172 .setVlanID(SERVER_VLAN.toShort())
1173 .setSourceMACAddress(SERVER_MAC)
1174 .setDestinationMACAddress(OUTER_RELAY_MAC)
1175 .setPayload(ipv4);
1176 } else {
1177 eth.setEtherType(Ethernet.TYPE_IPV4)
1178 .setVlanID(SERVER_VLAN.toShort())
1179 .setSourceMACAddress(SERVER_MAC)
1180 .setDestinationMACAddress(CLIENT_MAC)
1181 .setPayload(ipv4);
1182 }
1183
1184 this.inPacket = new DefaultInboundPacket(SERVER_CONNECT_POINT, eth,
1185 ByteBuffer.wrap(eth.serialize()));
1186
1187 }
1188
1189 @Override
1190 public InboundPacket inPacket() {
1191 return this.inPacket;
1192 }
1193 }
1194
1195 private class TestArpRequestPacketContext extends PacketContextAdapter {
1196 private InboundPacket inPacket;
1197
1198 public TestArpRequestPacketContext(Interface fromInterface) {
1199 super(0, null, null, false);
1200 ARP arp = new ARP();
1201 arp.setOpCode(ARP.OP_REQUEST);
1202
1203 IpAddress targetIp = fromInterface.ipAddressesList().get(0).ipAddress();
1204 arp.setTargetProtocolAddress(targetIp.toOctets());
1205 arp.setTargetHardwareAddress(MacAddress.BROADCAST.toBytes());
1206 arp.setSenderHardwareAddress(MacAddress.NONE.toBytes());
1207 arp.setSenderProtocolAddress(Ip4Address.valueOf(0).toOctets());
1208 arp.setHardwareAddressLength((byte) MacAddress.MAC_ADDRESS_LENGTH);
1209 Ethernet eth = new Ethernet();
1210 eth.setEtherType(Ethernet.TYPE_ARP);
1211 eth.setSourceMACAddress(MacAddress.NONE);
1212 eth.setDestinationMACAddress(MacAddress.BROADCAST);
1213 eth.setVlanID(fromInterface.vlan().toShort());
1214 eth.setPayload(arp);
1215
1216 this.inPacket = new DefaultInboundPacket(fromInterface.connectPoint(), eth,
1217 ByteBuffer.wrap(eth.serialize()));
1218 }
1219
1220 @Override
1221 public InboundPacket inPacket() {
1222 return this.inPacket;
1223 }
1224 }
Kalhee Kim45fede42017-09-05 19:05:06 +00001225
1226 /**
1227 * Generates DHCP6 REQUEST packet.
1228 */
1229 private void buildDhcp6Packet(DHCP6 dhcp6, byte msgType, Ip6Address ip6Addr, IpPrefix prefix) {
1230
1231 // build address option
1232 Dhcp6IaAddressOption iaAddressOption = new Dhcp6IaAddressOption();
1233 iaAddressOption.setCode(DHCP6.OptionCode.IAADDR.value());
1234 iaAddressOption.setIp6Address(ip6Addr);
1235 iaAddressOption.setPreferredLifetime(3600);
1236 iaAddressOption.setValidLifetime(1200);
1237 iaAddressOption.setLength((short) Dhcp6IaAddressOption.DEFAULT_LEN);
1238
Kalhee Kim495c9b22017-11-07 16:32:09 +00001239 Dhcp6ClientIdOption clientIdOption = new Dhcp6ClientIdOption();
1240 Dhcp6Duid dhcp6Duip = new Dhcp6Duid();
1241 dhcp6Duip.setDuidType(Dhcp6Duid.DuidType.DUID_LLT);
1242 dhcp6Duip.setHardwareType((short) 0x01); // Ethernet
1243 dhcp6Duip.setDuidTime(1234);
1244 dhcp6Duip.setLinkLayerAddress(CLIENT_MAC.toBytes());
1245 clientIdOption.setDuid(dhcp6Duip);
1246
Kalhee Kim45fede42017-09-05 19:05:06 +00001247 Dhcp6IaNaOption iaNaOption = new Dhcp6IaNaOption();
1248 iaNaOption.setCode(DHCP6.OptionCode.IA_NA.value());
1249 iaNaOption.setIaId(0);
1250 iaNaOption.setT1(302400);
1251 iaNaOption.setT2(483840);
1252 List<Dhcp6Option> iaNaSubOptions = new ArrayList<Dhcp6Option>();
1253 iaNaSubOptions.add(iaAddressOption);
1254 iaNaOption.setOptions(iaNaSubOptions);
1255 iaNaOption.setLength((short) (Dhcp6IaNaOption.DEFAULT_LEN + iaAddressOption.getLength()));
1256
1257 // build prefix option
1258 Dhcp6IaPrefixOption iaPrefixOption = new Dhcp6IaPrefixOption();
1259 iaPrefixOption.setCode(DHCP6.OptionCode.IAPREFIX.value());
1260 iaPrefixOption.setIp6Prefix(prefix.address().getIp6Address());
1261 iaPrefixOption.setPrefixLength((byte) prefix.prefixLength());
1262 iaPrefixOption.setPreferredLifetime(3601);
1263 iaPrefixOption.setValidLifetime(1201);
1264 iaPrefixOption.setLength((short) Dhcp6IaPrefixOption.DEFAULT_LEN);
1265
1266 Dhcp6IaPdOption iaPdOption = new Dhcp6IaPdOption();
1267 iaPdOption.setCode(DHCP6.OptionCode.IA_PD.value());
1268 iaPdOption.setIaId(0);
1269 iaPdOption.setT1(302401);
1270 iaPdOption.setT2(483841);
1271 List<Dhcp6Option> iaPdSubOptions = new ArrayList<Dhcp6Option>();
1272 iaPdSubOptions.add(iaPrefixOption);
1273 iaPdOption.setOptions(iaPdSubOptions);
1274 iaPdOption.setLength((short) (Dhcp6IaPdOption.DEFAULT_LEN + iaPrefixOption.getLength()));
1275
1276 dhcp6.setMsgType(msgType);
1277 List<Dhcp6Option> dhcp6Options = new ArrayList<Dhcp6Option>();
1278 dhcp6Options.add(iaNaOption);
Kalhee Kim495c9b22017-11-07 16:32:09 +00001279 dhcp6Options.add(clientIdOption);
Kalhee Kim45fede42017-09-05 19:05:06 +00001280 dhcp6Options.add(iaPdOption);
1281 dhcp6.setOptions(dhcp6Options);
1282
1283 }
1284
1285 private void buildRelayMsg(DHCP6 dhcp6Relay, byte msgType, Ip6Address linkAddr,
1286 Ip6Address peerAddr, byte hop, byte[] interfaceIdBytes,
1287 DHCP6 dhcp6Payload) {
1288
1289 dhcp6Relay.setMsgType(msgType);
1290
1291 dhcp6Relay.setLinkAddress(linkAddr.toOctets());
1292 dhcp6Relay.setPeerAddress(peerAddr.toOctets());
1293 dhcp6Relay.setHopCount(hop);
1294 List<Dhcp6Option> options = new ArrayList<Dhcp6Option>();
1295
1296 // interfaceId option
1297 Dhcp6Option interfaceId = new Dhcp6Option();
1298 interfaceId.setCode(DHCP6.OptionCode.INTERFACE_ID.value());
1299
1300
1301 interfaceId.setData(interfaceIdBytes);
1302 interfaceId.setLength((short) interfaceIdBytes.length);
1303 Dhcp6InterfaceIdOption interfaceIdOption = new Dhcp6InterfaceIdOption(interfaceId);
Kalhee Kima0b8f652017-10-18 22:00:30 +00001304 byte[] optionData = interfaceIdOption.getData();
Kalhee Kim45fede42017-09-05 19:05:06 +00001305 ByteBuffer bb = ByteBuffer.wrap(interfaceIdBytes);
1306
1307 byte[] macAddr = new byte[MacAddress.MAC_ADDRESS_LENGTH];
Kalhee Kima0b8f652017-10-18 22:00:30 +00001308 byte[] port = new byte[optionData.length - MacAddress.MAC_ADDRESS_LENGTH -
Kalhee Kimba366062017-11-07 16:32:09 +00001309 VLAN_LEN - SEPARATOR_LEN * 2];
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001310 short vlan;
Kalhee Kim45fede42017-09-05 19:05:06 +00001311 bb.get(macAddr);
1312 bb.get(); // separator
1313 bb.get(port);
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001314 bb.get(); // separator
1315 vlan = bb.getShort();
Kalhee Kim45fede42017-09-05 19:05:06 +00001316 interfaceIdOption.setMacAddress(MacAddress.valueOf(macAddr));
1317 interfaceIdOption.setInPort(port);
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001318 interfaceIdOption.setVlanId(vlan);
Kalhee Kim45fede42017-09-05 19:05:06 +00001319
1320 options.add(interfaceIdOption);
1321
1322 // relay message option
1323 Dhcp6Option relayMsgOption = new Dhcp6Option();
1324 relayMsgOption.setCode(DHCP6.OptionCode.RELAY_MSG.value());
1325 byte[] dhcp6PayloadByte = dhcp6Payload.serialize();
1326 relayMsgOption.setLength((short) dhcp6PayloadByte.length);
1327 relayMsgOption.setPayload(dhcp6Payload);
1328 Dhcp6RelayOption relayOpt = new Dhcp6RelayOption(relayMsgOption);
1329
1330 options.add(relayOpt);
1331
1332 dhcp6Relay.setOptions(options);
1333 }
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001334 private byte[] buildInterfaceId(MacAddress clientMac, short vlanId, ConnectPoint clientCp) {
1335 String inPortString = "-" + clientCp.toString() + ":";
Kalhee Kim45fede42017-09-05 19:05:06 +00001336 byte[] clientSoureMacBytes = clientMac.toBytes();
1337 byte[] inPortStringBytes = inPortString.getBytes();
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001338 byte[] vlanIdBytes = new byte[2];
1339 vlanIdBytes[0] = (byte) ((vlanId >> 8) & 0xff); // high-order byte first
1340 vlanIdBytes[1] = (byte) (vlanId & 0xff);
1341 byte[] interfaceIdBytes = new byte[clientSoureMacBytes.length + inPortStringBytes.length + vlanIdBytes.length];
Kalhee Kim45fede42017-09-05 19:05:06 +00001342
1343 System.arraycopy(clientSoureMacBytes, 0, interfaceIdBytes, 0, clientSoureMacBytes.length);
1344 System.arraycopy(inPortStringBytes, 0, interfaceIdBytes, clientSoureMacBytes.length, inPortStringBytes.length);
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001345 System.arraycopy(vlanIdBytes, 0, interfaceIdBytes, clientSoureMacBytes.length + inPortStringBytes.length,
1346 vlanIdBytes.length);
Kalhee Kim45fede42017-09-05 19:05:06 +00001347
1348 return interfaceIdBytes;
1349 }
1350
Yi Tseng525ff402017-10-23 19:39:39 -07001351 private static List<TrafficSelector> buildClientDhcpSelectors() {
1352 return Streams.concat(Dhcp4HandlerImpl.DHCP_SELECTORS.stream(),
1353 Dhcp6HandlerImpl.DHCP_SELECTORS.stream())
1354 .collect(Collectors.toList());
1355 }
1356
Kalhee Kim45fede42017-09-05 19:05:06 +00001357 private class TestDhcp6RequestPacketContext extends PacketContextAdapter {
1358
1359
1360 private InboundPacket inPacket;
1361
1362
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001363 public TestDhcp6RequestPacketContext(byte msgType, MacAddress clientMac, VlanId vlanId,
Kalhee Kim45fede42017-09-05 19:05:06 +00001364 ConnectPoint clientCp,
1365 Ip6Address clientGwAddr,
1366 int relayLevel) {
1367 super(0, null, null, false);
1368
1369 DHCP6 dhcp6 = new DHCP6();
1370 if (relayLevel > 0) {
1371 DHCP6 dhcp6Payload = new DHCP6();
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001372 buildDhcp6Packet(dhcp6Payload, msgType,
Kalhee Kim45fede42017-09-05 19:05:06 +00001373 IP_FOR_CLIENT_V6,
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001374 msgType == DHCP6.MsgType.REQUEST.value() ? PREFIX_FOR_ZERO : PREFIX_FOR_CLIENT_V6);
Kalhee Kim45fede42017-09-05 19:05:06 +00001375 DHCP6 dhcp6Parent = null;
1376 DHCP6 dhcp6Child = dhcp6Payload;
1377 for (int i = 0; i < relayLevel; i++) {
1378 dhcp6Parent = new DHCP6();
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001379 byte[] interfaceId = buildInterfaceId(clientMac, vlanId.toShort(), clientCp);
Kalhee Kim45fede42017-09-05 19:05:06 +00001380 buildRelayMsg(dhcp6Parent, DHCP6.MsgType.RELAY_FORW.value(),
1381 INTERFACE_IP_V6.ipAddress().getIp6Address(),
1382 OUTER_RELAY_IP_V6,
1383 (byte) (relayLevel - 1), interfaceId,
1384 dhcp6Child);
1385 dhcp6Child = dhcp6Parent;
1386 }
1387 if (dhcp6Parent != null) {
1388 dhcp6 = dhcp6Parent;
1389 }
1390 } else {
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001391 buildDhcp6Packet(dhcp6, msgType,
Kalhee Kim45fede42017-09-05 19:05:06 +00001392 IP_FOR_CLIENT_V6,
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001393 msgType == DHCP6.MsgType.REQUEST.value() ? PREFIX_FOR_ZERO : PREFIX_FOR_CLIENT_V6);
Kalhee Kim45fede42017-09-05 19:05:06 +00001394 }
1395
1396 UDP udp = new UDP();
1397 udp.setPayload(dhcp6);
1398 if (relayLevel > 0) {
1399 udp.setSourcePort(UDP.DHCP_V6_SERVER_PORT);
1400 } else {
1401 udp.setSourcePort(UDP.DHCP_V6_CLIENT_PORT);
1402 }
1403 udp.setDestinationPort(UDP.DHCP_V6_SERVER_PORT);
1404
1405 IPv6 ipv6 = new IPv6();
1406 ipv6.setPayload(udp);
1407 ipv6.setNextHeader(IPv6.PROTOCOL_UDP);
1408 ipv6.setDestinationAddress(SERVER_IP_V6_MCAST.toOctets());
1409 ipv6.setSourceAddress(clientGwAddr.toOctets());
1410
1411 Ethernet eth = new Ethernet();
1412 if (relayLevel > 0) {
1413 eth.setEtherType(Ethernet.TYPE_IPV6)
Kalhee Kim121ba922017-11-01 17:56:44 +00001414 .setVlanID(OUTER_RELAY_VLAN.toShort())
Kalhee Kim45fede42017-09-05 19:05:06 +00001415 .setSourceMACAddress(OUTER_RELAY_MAC)
1416 .setDestinationMACAddress(MacAddress.valueOf("33:33:00:01:00:02"))
1417 .setPayload(ipv6);
1418 } else {
1419 eth.setEtherType(Ethernet.TYPE_IPV6)
1420 .setVlanID(vlanId.toShort())
1421 .setSourceMACAddress(clientMac)
1422 .setDestinationMACAddress(MacAddress.valueOf("33:33:00:01:00:02"))
1423 .setPayload(ipv6);
1424 }
1425 this.inPacket = new DefaultInboundPacket(clientCp, eth,
1426 ByteBuffer.wrap(eth.serialize()));
1427 }
1428
1429 @Override
1430 public InboundPacket inPacket() {
1431 return this.inPacket;
1432 }
1433 }
1434
1435 /**
1436 * Generates DHCP6 REPLY packet.
1437 */
1438
1439 private class TestDhcp6ReplyPacketContext extends PacketContextAdapter {
1440 private InboundPacket inPacket;
1441
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001442 public TestDhcp6ReplyPacketContext(byte msgType, ConnectPoint clientCp, MacAddress clientMac,
Kalhee Kim45fede42017-09-05 19:05:06 +00001443 VlanId clientVlan, Ip6Address clientGwAddr,
Kalhee Kim121ba922017-11-01 17:56:44 +00001444 int relayLevel, boolean overWriteFlag, VlanId overWriteVlan) {
Kalhee Kim45fede42017-09-05 19:05:06 +00001445 super(0, null, null, false);
1446
1447
1448 DHCP6 dhcp6Payload = new DHCP6();
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001449 buildDhcp6Packet(dhcp6Payload, msgType,
Kalhee Kim45fede42017-09-05 19:05:06 +00001450 IP_FOR_CLIENT_V6,
1451 PREFIX_FOR_CLIENT_V6);
Kalhee Kim121ba922017-11-01 17:56:44 +00001452 byte[] interfaceId = null;
1453 if (relayLevel > 0) {
1454 interfaceId = buildInterfaceId(OUTER_RELAY_MAC,
1455 overWriteFlag ? overWriteVlan.toShort() : OUTER_RELAY_VLAN.toShort(),
1456 OUTER_RELAY_CP);
1457 } else {
1458 interfaceId = buildInterfaceId(clientMac, clientVlan.toShort(), clientCp);
1459 }
Kalhee Kim45fede42017-09-05 19:05:06 +00001460 DHCP6 dhcp6 = new DHCP6();
1461 buildRelayMsg(dhcp6, DHCP6.MsgType.RELAY_REPL.value(),
Yi Tsengaa417a62017-09-08 17:22:51 -07001462 INTERFACE_IP_V6.ipAddress().getIp6Address(),
1463 CLIENT_LL_IP_V6,
1464 (byte) 0, interfaceId,
1465 dhcp6Payload);
Kalhee Kim45fede42017-09-05 19:05:06 +00001466
1467 DHCP6 dhcp6Parent = null;
1468 DHCP6 dhcp6Child = dhcp6;
1469 for (int i = 0; i < relayLevel; i++) { // relayLevel 0 : no relay
1470 dhcp6Parent = new DHCP6();
1471
1472 buildRelayMsg(dhcp6Parent, DHCP6.MsgType.RELAY_REPL.value(),
1473 INTERFACE_IP_V6.ipAddress().getIp6Address(),
1474 OUTER_RELAY_IP_V6,
1475 (byte) relayLevel, interfaceId,
1476 dhcp6Child);
1477
1478 dhcp6Child = dhcp6Parent;
1479 }
1480 if (dhcp6Parent != null) {
1481 dhcp6 = dhcp6Parent;
1482 }
1483
1484
1485 UDP udp = new UDP();
1486 udp.setPayload(dhcp6);
1487 udp.setSourcePort(UDP.DHCP_V6_SERVER_PORT);
1488 udp.setDestinationPort(UDP.DHCP_V6_CLIENT_PORT);
1489 IPv6 ipv6 = new IPv6();
1490 ipv6.setPayload(udp);
1491 ipv6.setNextHeader(IPv6.PROTOCOL_UDP);
1492 ipv6.setDestinationAddress(IP_FOR_CLIENT_V6.toOctets());
1493 ipv6.setSourceAddress(SERVER_IP_V6.toOctets());
1494 Ethernet eth = new Ethernet();
1495 if (relayLevel > 0) {
1496 eth.setEtherType(Ethernet.TYPE_IPV6)
1497 .setVlanID(SERVER_VLAN.toShort())
1498 .setSourceMACAddress(SERVER_MAC)
1499 .setDestinationMACAddress(OUTER_RELAY_MAC)
1500 .setPayload(ipv6);
1501 } else {
1502 eth.setEtherType(Ethernet.TYPE_IPV6)
1503 .setVlanID(SERVER_VLAN.toShort())
1504 .setSourceMACAddress(SERVER_MAC)
1505 .setDestinationMACAddress(CLIENT_MAC)
1506 .setPayload(ipv6);
1507 }
1508
1509 this.inPacket = new DefaultInboundPacket(SERVER_CONNECT_POINT, eth,
1510 ByteBuffer.wrap(eth.serialize()));
1511
1512 }
1513
1514 @Override
1515 public InboundPacket inPacket() {
1516 return this.inPacket;
1517 }
1518 }
1519
Yi Tseng7a38f9a2017-06-09 14:36:40 -07001520}