blob: 7efed1a520681de67751632b5cebd51d5ce7f3da [file] [log] [blame]
Yi Tseng7a38f9a2017-06-09 14:36:40 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Yi Tseng7a38f9a2017-06-09 14:36:40 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.dhcprelay;
17
Yi Tseng51f1be92017-09-01 17:24:57 -070018import com.fasterxml.jackson.databind.JsonNode;
19import com.fasterxml.jackson.databind.ObjectMapper;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070020import com.google.common.collect.ImmutableList;
21import com.google.common.collect.ImmutableSet;
22import com.google.common.collect.Lists;
23import com.google.common.collect.Maps;
24import com.google.common.collect.Sets;
Yi Tseng525ff402017-10-23 19:39:39 -070025import com.google.common.collect.Streams;
Yi Tseng51f1be92017-09-01 17:24:57 -070026import com.google.common.io.Resources;
Yi Tseng440e2b72017-08-24 14:47:34 -070027import org.apache.commons.io.Charsets;
Yi Tseng51f1be92017-09-01 17:24:57 -070028import org.easymock.Capture;
29import org.easymock.CaptureType;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070030import org.easymock.EasyMock;
31import org.junit.After;
32import org.junit.Before;
33import org.junit.Test;
34import org.onlab.packet.ARP;
35import org.onlab.packet.DHCP;
Yi Tseng3df7f9d2017-08-17 13:08:31 -070036import org.onlab.packet.DeserializationException;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070037import org.onlab.packet.Ethernet;
38import org.onlab.packet.IPv4;
39import org.onlab.packet.Ip4Address;
Kalhee Kim45fede42017-09-05 19:05:06 +000040import org.onlab.packet.Ip6Address;
41import org.onlab.packet.IpPrefix;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070042import org.onlab.packet.IpAddress;
43import org.onlab.packet.MacAddress;
44import org.onlab.packet.UDP;
45import org.onlab.packet.VlanId;
46import org.onlab.packet.dhcp.CircuitId;
47import org.onlab.packet.dhcp.DhcpOption;
48import org.onlab.packet.dhcp.DhcpRelayAgentOption;
Kalhee Kim45fede42017-09-05 19:05:06 +000049import org.onlab.packet.dhcp.Dhcp6InterfaceIdOption;
50import org.onlab.packet.dhcp.Dhcp6RelayOption;
51import org.onlab.packet.dhcp.Dhcp6IaNaOption;
52import org.onlab.packet.dhcp.Dhcp6IaPdOption;
53import org.onlab.packet.dhcp.Dhcp6IaAddressOption;
54import org.onlab.packet.dhcp.Dhcp6IaPrefixOption;
55import org.onlab.packet.dhcp.Dhcp6Option;
56import org.onosproject.net.ConnectPoint;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070057import org.onosproject.TestApplicationId;
58import org.onosproject.cfg.ComponentConfigService;
59import org.onosproject.core.ApplicationId;
60import org.onosproject.core.CoreService;
Yi Tseng483ac6f2017-08-02 15:03:31 -070061import org.onosproject.dhcprelay.config.DefaultDhcpRelayConfig;
62import org.onosproject.dhcprelay.config.DhcpServerConfig;
Yi Tseng51f1be92017-09-01 17:24:57 -070063import org.onosproject.dhcprelay.config.IgnoreDhcpConfig;
Yi Tseng483ac6f2017-08-02 15:03:31 -070064import org.onosproject.dhcprelay.config.IndirectDhcpRelayConfig;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070065import org.onosproject.dhcprelay.store.DhcpRecord;
66import org.onosproject.dhcprelay.store.DhcpRelayStore;
67import org.onosproject.dhcprelay.store.DhcpRelayStoreEvent;
Yi Tseng127ffe52017-09-12 15:55:17 -070068import org.onosproject.net.Device;
Yi Tseng51f1be92017-09-01 17:24:57 -070069import org.onosproject.net.DeviceId;
Yi Tseng127ffe52017-09-12 15:55:17 -070070import org.onosproject.net.behaviour.Pipeliner;
71import org.onosproject.net.device.DeviceEvent;
72import org.onosproject.net.device.DeviceService;
Yi Tseng51f1be92017-09-01 17:24:57 -070073import org.onosproject.net.flow.DefaultTrafficSelector;
74import org.onosproject.net.flow.DefaultTrafficTreatment;
75import org.onosproject.net.flow.TrafficSelector;
76import org.onosproject.net.flow.TrafficTreatment;
77import org.onosproject.net.flowobjective.FlowObjectiveService;
78import org.onosproject.net.flowobjective.ForwardingObjective;
79import org.onosproject.net.flowobjective.Objective;
Yi Tsengaa417a62017-09-08 17:22:51 -070080import org.onosproject.net.host.HostProviderService;
Ray Milkeyfacf2862017-08-03 11:58:29 -070081import org.onosproject.net.intf.Interface;
82import org.onosproject.net.intf.InterfaceServiceAdapter;
Yi Tseng51f1be92017-09-01 17:24:57 -070083import org.onosproject.net.packet.PacketPriority;
Ray Milkey69ec8712017-08-08 13:00:43 -070084import org.onosproject.routeservice.Route;
85import org.onosproject.routeservice.RouteStoreAdapter;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070086import org.onosproject.net.DefaultHost;
87import org.onosproject.net.Host;
88import org.onosproject.net.HostId;
89import org.onosproject.net.HostLocation;
90import org.onosproject.net.config.NetworkConfigRegistry;
91import org.onosproject.net.host.HostDescription;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070092import org.onosproject.net.host.HostService;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070093import org.onosproject.net.host.InterfaceIpAddress;
94import org.onosproject.net.packet.DefaultInboundPacket;
95import org.onosproject.net.packet.InboundPacket;
96import org.onosproject.net.packet.OutboundPacket;
97import org.onosproject.net.packet.PacketContext;
98import org.onosproject.net.packet.PacketContextAdapter;
99import org.onosproject.net.packet.PacketProcessor;
100import org.onosproject.net.packet.PacketServiceAdapter;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700101import org.onosproject.store.StoreDelegate;
102import org.osgi.service.component.ComponentContext;
Kalhee Kim45fede42017-09-05 19:05:06 +0000103import org.onlab.packet.DHCP6;
104import org.onlab.packet.IPv6;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700105
Yi Tseng127ffe52017-09-12 15:55:17 -0700106import java.io.IOException;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700107import java.nio.ByteBuffer;
108import java.util.Collection;
109import java.util.Dictionary;
110import java.util.List;
Kalhee Kim45fede42017-09-05 19:05:06 +0000111import java.util.ArrayList;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700112import java.util.Map;
113import java.util.Optional;
114import java.util.Set;
115import java.util.stream.Collectors;
116
117import static org.easymock.EasyMock.*;
118import static org.junit.Assert.*;
Yi Tseng51f1be92017-09-01 17:24:57 -0700119import static org.onosproject.dhcprelay.DhcpRelayManager.DHCP_RELAY_APP;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700120
121public class DhcpRelayManagerTest {
Kalhee Kima0b8f652017-10-18 22:00:30 +0000122 private static final short VLAN_LEN = 2;
123 private static final short SEPARATOR_LEN = 1;
Yi Tseng51f1be92017-09-01 17:24:57 -0700124 private static final String CONFIG_FILE_PATH = "dhcp-relay.json";
125 private static final DeviceId DEV_1_ID = DeviceId.deviceId("of:0000000000000001");
126 private static final DeviceId DEV_2_ID = DeviceId.deviceId("of:0000000000000002");
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700127 // Ip address for interfaces
128 private static final InterfaceIpAddress INTERFACE_IP = InterfaceIpAddress.valueOf("10.0.3.254/32");
Kalhee Kim45fede42017-09-05 19:05:06 +0000129 private static final InterfaceIpAddress INTERFACE_IP_V6 = InterfaceIpAddress.valueOf("2001:db8:1::254/128");
130 private static final List<InterfaceIpAddress> INTERFACE_IPS = ImmutableList.of(INTERFACE_IP, INTERFACE_IP_V6);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700131
132 // DHCP client (will send without option 82)
133 private static final Ip4Address IP_FOR_CLIENT = Ip4Address.valueOf("10.0.0.1");
Kalhee Kim45fede42017-09-05 19:05:06 +0000134 private static final Ip6Address IP_FOR_CLIENT_V6 = Ip6Address.valueOf("2001:db8:1::110");
135 private static final IpPrefix PREFIX_FOR_CLIENT_V6 = IpPrefix.valueOf("2001:db8:10::/56");
136 private static final IpPrefix PREFIX_FOR_ZERO = IpPrefix.valueOf("::/0");
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700137 private static final MacAddress CLIENT_MAC = MacAddress.valueOf("00:00:00:00:00:01");
138 private static final VlanId CLIENT_VLAN = VlanId.vlanId("100");
139 private static final ConnectPoint CLIENT_CP = ConnectPoint.deviceConnectPoint("of:0000000000000001/1");
140 private static final MacAddress CLIENT_IFACE_MAC = MacAddress.valueOf("00:00:00:00:11:01");
Yi Tsengaa417a62017-09-08 17:22:51 -0700141 private static final HostLocation CLIENT_LOCATION = new HostLocation(CLIENT_CP, 0);
142 private static final HostId CLIENT_HOST_ID = HostId.hostId(CLIENT_MAC, CLIENT_VLAN);
143 private static final Ip6Address CLIENT_LL_IP_V6 = Ip6Address.valueOf("fe80::200:00ff:fe00:0001");
Charles Chand988c282017-09-12 17:09:32 -0700144 private static final Host EXISTS_HOST = new DefaultHost(Dhcp4HandlerImpl.PROVIDER_ID,
Yi Tsengaa417a62017-09-08 17:22:51 -0700145 CLIENT_HOST_ID, CLIENT_MAC, CLIENT_VLAN,
146 CLIENT_LOCATION, ImmutableSet.of(CLIENT_LL_IP_V6));
Yi Tseng4025a102017-09-30 11:35:42 +0800147 private static final Interface CLIENT_INTERFACE = createInterface("C1",
148 CLIENT_CP,
149 INTERFACE_IPS,
150 CLIENT_IFACE_MAC,
151 CLIENT_VLAN,
152 null);
153
154
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700155
Yi Tsengaa417a62017-09-08 17:22:51 -0700156 // Dual homing test
157 private static final ConnectPoint CLIENT_DH_CP = ConnectPoint.deviceConnectPoint("of:0000000000000001/3");
158 private static final HostLocation CLIENT_DH_LOCATION = new HostLocation(CLIENT_DH_CP, 0);
Yi Tseng4025a102017-09-30 11:35:42 +0800159 private static final Interface CLIENT_DH_INTERFACE = createInterface("C1-DH",
160 CLIENT_DH_CP,
161 INTERFACE_IPS,
162 CLIENT_IFACE_MAC,
163 CLIENT_VLAN,
164 null);
Yi Tsengaa417a62017-09-08 17:22:51 -0700165
166
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700167 // DHCP client 2 (will send with option 82, so the vlan should equals to vlan from server)
168 private static final MacAddress CLIENT2_MAC = MacAddress.valueOf("00:00:00:00:00:01");
169 private static final VlanId CLIENT2_VLAN = VlanId.NONE;
Yi Tseng4025a102017-09-30 11:35:42 +0800170 private static final VlanId CLIENT2_VLAN_NATIVE = VlanId.vlanId("20");
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700171 private static final ConnectPoint CLIENT2_CP = ConnectPoint.deviceConnectPoint("of:0000000000000001/2");
172 private static final MacAddress CLIENT2_IFACE_MAC = MacAddress.valueOf("00:00:00:00:11:01");
Yi Tseng4025a102017-09-30 11:35:42 +0800173 private static final Interface CLIENT2_INTERFACE = createInterface("C2",
174 CLIENT2_CP,
175 INTERFACE_IPS,
176 CLIENT2_IFACE_MAC,
177 CLIENT2_VLAN,
178 CLIENT2_VLAN_NATIVE);
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000179 private static final VlanId CLIENT_BOGUS_VLAN = VlanId.vlanId("108");
180
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700181 // Outer relay information
Kalhee Kim121ba922017-11-01 17:56:44 +0000182 private static final Ip4Address OUTER_RELAY_IP = Ip4Address.valueOf("10.0.6.253");
Kalhee Kim45fede42017-09-05 19:05:06 +0000183 private static final Ip6Address OUTER_RELAY_IP_V6 = Ip6Address.valueOf("2001:db8:1::4");
Kalhee Kim121ba922017-11-01 17:56:44 +0000184 private static final Ip6Address OUTER_RELAY_LL_IP_V6 = Ip6Address.valueOf("fe80::200:0102:0304:0501");
185 private static final Set<IpAddress> OUTER_RELAY_IPS = ImmutableSet.of(OUTER_RELAY_IP,
186 OUTER_RELAY_IP_V6,
187 OUTER_RELAY_LL_IP_V6);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700188 private static final MacAddress OUTER_RELAY_MAC = MacAddress.valueOf("00:01:02:03:04:05");
189 private static final VlanId OUTER_RELAY_VLAN = VlanId.NONE;
190 private static final ConnectPoint OUTER_RELAY_CP = ConnectPoint.deviceConnectPoint("of:0000000000000001/2");
191 private static final HostLocation OUTER_REPLAY_HL = new HostLocation(OUTER_RELAY_CP, 0);
192 private static final HostId OUTER_RELAY_HOST_ID = HostId.hostId(OUTER_RELAY_MAC, OUTER_RELAY_VLAN);
Charles Chand988c282017-09-12 17:09:32 -0700193 private static final Host OUTER_RELAY_HOST = new DefaultHost(Dhcp4HandlerImpl.PROVIDER_ID,
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700194 OUTER_RELAY_HOST_ID,
195 OUTER_RELAY_MAC,
196 OUTER_RELAY_VLAN,
197 OUTER_REPLAY_HL,
198 OUTER_RELAY_IPS);
199
200 // DHCP Server
201 private static final MacAddress SERVER_MAC = MacAddress.valueOf("00:00:00:00:00:01");
202 private static final VlanId SERVER_VLAN = VlanId.NONE;
Yi Tseng4025a102017-09-30 11:35:42 +0800203 private static final VlanId SERVER_VLAN_NATIVE = VlanId.vlanId("10");
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700204 private static final ConnectPoint SERVER_CONNECT_POINT =
205 ConnectPoint.deviceConnectPoint("of:0000000000000001/5");
206 private static final HostLocation SERVER_LOCATION =
207 new HostLocation(SERVER_CONNECT_POINT, 0);
Kalhee Kim45fede42017-09-05 19:05:06 +0000208 private static final Ip4Address GATEWAY_IP = Ip4Address.valueOf("10.0.5.253");
209 private static final Ip6Address GATEWAY_IP_V6 = Ip6Address.valueOf("2000::105:253");
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700210 private static final Ip4Address SERVER_IP = Ip4Address.valueOf("10.0.3.253");
Kalhee Kim45fede42017-09-05 19:05:06 +0000211 private static final Ip6Address SERVER_IP_V6 = Ip6Address.valueOf("2000::103:253");
212 private static final Ip6Address SERVER_IP_V6_MCAST = Ip6Address.valueOf("ff02::1:2");
213 private static final Set<IpAddress> DHCP_SERVER_IPS = ImmutableSet.of(SERVER_IP, SERVER_IP_V6);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700214 private static final HostId SERVER_HOST_ID = HostId.hostId(SERVER_MAC, SERVER_VLAN);
Charles Chand988c282017-09-12 17:09:32 -0700215 private static final Host SERVER_HOST = new DefaultHost(Dhcp4HandlerImpl.PROVIDER_ID,
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700216 SERVER_HOST_ID,
217 SERVER_MAC,
218 SERVER_VLAN,
219 SERVER_LOCATION,
220 DHCP_SERVER_IPS);
221 private static final MacAddress SERVER_IFACE_MAC = MacAddress.valueOf("00:00:00:00:00:01");
Yi Tseng4025a102017-09-30 11:35:42 +0800222 private static final Interface SERVER_INTERFACE = createInterface("SERVER",
223 SERVER_CONNECT_POINT,
224 INTERFACE_IPS,
225 SERVER_IFACE_MAC,
226 SERVER_VLAN,
227 SERVER_VLAN_NATIVE);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700228
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700229 // Relay agent config
230 private static final Ip4Address RELAY_AGENT_IP = Ip4Address.valueOf("10.0.4.254");
231
Yi Tseng525ff402017-10-23 19:39:39 -0700232 private static final List<TrafficSelector> DHCP_SELECTORS = buildClientDhcpSelectors();
233
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700234 // Components
235 private static final ApplicationId APP_ID = TestApplicationId.create(DhcpRelayManager.DHCP_RELAY_APP);
Yi Tseng483ac6f2017-08-02 15:03:31 -0700236 private static final DefaultDhcpRelayConfig CONFIG = new MockDefaultDhcpRelayConfig();
Kalhee Kim45fede42017-09-05 19:05:06 +0000237 private static final IndirectDhcpRelayConfig CONFIG_INDIRECT = new MockIndirectDhcpRelayConfig();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700238 private static final Set<Interface> INTERFACES = ImmutableSet.of(
239 CLIENT_INTERFACE,
240 CLIENT2_INTERFACE,
Yi Tsengaa417a62017-09-08 17:22:51 -0700241 SERVER_INTERFACE,
242 CLIENT_DH_INTERFACE
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700243 );
Yi Tseng440e2b72017-08-24 14:47:34 -0700244 private static final String NON_ONOS_CID = "Non-ONOS circuit ID";
Yi Tseng51f1be92017-09-01 17:24:57 -0700245 private static final VlanId IGNORED_VLAN = VlanId.vlanId("100");
246 private static final int IGNORE_CONTROL_PRIORITY = PacketPriority.CONTROL.priorityValue() + 1000;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700247
248 private DhcpRelayManager manager;
249 private MockPacketService packetService;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700250 private MockRouteStore mockRouteStore;
251 private MockDhcpRelayStore mockDhcpRelayStore;
Yi Tsengaa417a62017-09-08 17:22:51 -0700252 private HostProviderService mockHostProviderService;
Yi Tseng525ff402017-10-23 19:39:39 -0700253 private FlowObjectiveService flowObjectiveService;
254 private DeviceService deviceService;
255 private Dhcp4HandlerImpl v4Handler;
256 private Dhcp6HandlerImpl v6Handler;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700257
Yi Tseng4025a102017-09-30 11:35:42 +0800258 private static Interface createInterface(String name, ConnectPoint connectPoint,
259 List<InterfaceIpAddress> interfaceIps,
260 MacAddress macAddress,
261 VlanId vlanId,
262 VlanId vlanNative) {
263
264 if (vlanId.equals(VlanId.NONE)) {
265 return new Interface(name, connectPoint, interfaceIps, macAddress, vlanId,
266 null, null, vlanNative);
267 } else {
268 return new Interface(name, connectPoint, interfaceIps, macAddress, vlanId,
269 null, ImmutableSet.of(vlanId), null);
270 }
271 }
272
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700273 @Before
274 public void setup() {
275 manager = new DhcpRelayManager();
276 manager.cfgService = createNiceMock(NetworkConfigRegistry.class);
277
Yi Tseng483ac6f2017-08-02 15:03:31 -0700278 expect(manager.cfgService.getConfig(APP_ID, DefaultDhcpRelayConfig.class))
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700279 .andReturn(CONFIG)
280 .anyTimes();
281
Yi Tseng483ac6f2017-08-02 15:03:31 -0700282 expect(manager.cfgService.getConfig(APP_ID, IndirectDhcpRelayConfig.class))
Kalhee Kim45fede42017-09-05 19:05:06 +0000283 .andReturn(CONFIG_INDIRECT)
Yi Tseng483ac6f2017-08-02 15:03:31 -0700284 .anyTimes();
285
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700286 manager.coreService = createNiceMock(CoreService.class);
287 expect(manager.coreService.registerApplication(anyString()))
288 .andReturn(APP_ID).anyTimes();
289
290 manager.hostService = createNiceMock(HostService.class);
Kalhee Kim121ba922017-11-01 17:56:44 +0000291
292 expect(manager.hostService.getHostsByIp(OUTER_RELAY_IP_V6))
293 .andReturn(ImmutableSet.of(OUTER_RELAY_HOST)).anyTimes();
294 expect(manager.hostService.getHostsByIp(SERVER_IP))
295 .andReturn(ImmutableSet.of(SERVER_HOST)).anyTimes();
296 expect(manager.hostService.getHostsByIp(SERVER_IP_V6))
297 .andReturn(ImmutableSet.of(SERVER_HOST)).anyTimes();
298 expect(manager.hostService.getHostsByIp(GATEWAY_IP))
299 .andReturn(ImmutableSet.of(SERVER_HOST)).anyTimes();
300 expect(manager.hostService.getHostsByIp(GATEWAY_IP_V6))
301 .andReturn(ImmutableSet.of(SERVER_HOST)).anyTimes();
302 expect(manager.hostService.getHostsByIp(CLIENT_LL_IP_V6))
303 .andReturn(ImmutableSet.of(EXISTS_HOST)).anyTimes();
304
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700305 expect(manager.hostService.getHost(OUTER_RELAY_HOST_ID)).andReturn(OUTER_RELAY_HOST).anyTimes();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700306
307 packetService = new MockPacketService();
308 manager.packetService = packetService;
309 manager.compCfgService = createNiceMock(ComponentConfigService.class);
Yi Tseng525ff402017-10-23 19:39:39 -0700310 deviceService = createNiceMock(DeviceService.class);
Yi Tseng127ffe52017-09-12 15:55:17 -0700311
312 Device device = createNiceMock(Device.class);
313 expect(device.is(Pipeliner.class)).andReturn(true).anyTimes();
314
Yi Tseng525ff402017-10-23 19:39:39 -0700315 expect(deviceService.getDevice(DEV_1_ID)).andReturn(device).anyTimes();
316 expect(deviceService.getDevice(DEV_2_ID)).andReturn(device).anyTimes();
317 replay(deviceService, device);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700318
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700319 mockRouteStore = new MockRouteStore();
320 mockDhcpRelayStore = new MockDhcpRelayStore();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700321 manager.dhcpRelayStore = mockDhcpRelayStore;
Yi Tseng525ff402017-10-23 19:39:39 -0700322 manager.deviceService = deviceService;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700323
324 manager.interfaceService = new MockInterfaceService();
Yi Tseng525ff402017-10-23 19:39:39 -0700325 flowObjectiveService = EasyMock.niceMock(FlowObjectiveService.class);
Yi Tsengaa417a62017-09-08 17:22:51 -0700326 mockHostProviderService = createNiceMock(HostProviderService.class);
Yi Tseng525ff402017-10-23 19:39:39 -0700327 v4Handler = new Dhcp4HandlerImpl();
Yi Tsengaa417a62017-09-08 17:22:51 -0700328 v4Handler.providerService = mockHostProviderService;
Yi Tseng51301292017-07-28 13:02:59 -0700329 v4Handler.dhcpRelayStore = mockDhcpRelayStore;
330 v4Handler.hostService = manager.hostService;
Yi Tseng51301292017-07-28 13:02:59 -0700331 v4Handler.interfaceService = manager.interfaceService;
332 v4Handler.packetService = manager.packetService;
333 v4Handler.routeStore = mockRouteStore;
Yi Tseng525ff402017-10-23 19:39:39 -0700334 v4Handler.coreService = createNiceMock(CoreService.class);
335 v4Handler.flowObjectiveService = flowObjectiveService;
336 v4Handler.appId = TestApplicationId.create(Dhcp4HandlerImpl.DHCP_V4_RELAY_APP);
337 v4Handler.deviceService = deviceService;
Yi Tseng51301292017-07-28 13:02:59 -0700338 manager.v4Handler = v4Handler;
339
Yi Tseng525ff402017-10-23 19:39:39 -0700340 v6Handler = new Dhcp6HandlerImpl();
Kalhee Kim45fede42017-09-05 19:05:06 +0000341 v6Handler.dhcpRelayStore = mockDhcpRelayStore;
342 v6Handler.hostService = manager.hostService;
Kalhee Kim45fede42017-09-05 19:05:06 +0000343 v6Handler.interfaceService = manager.interfaceService;
344 v6Handler.packetService = manager.packetService;
345 v6Handler.routeStore = mockRouteStore;
Yi Tsengaa417a62017-09-08 17:22:51 -0700346 v6Handler.providerService = mockHostProviderService;
Yi Tseng525ff402017-10-23 19:39:39 -0700347 v6Handler.coreService = createNiceMock(CoreService.class);
348 v6Handler.flowObjectiveService = flowObjectiveService;
349 v6Handler.appId = TestApplicationId.create(Dhcp6HandlerImpl.DHCP_V6_RELAY_APP);
350 v6Handler.deviceService = deviceService;
Yi Tseng483ac6f2017-08-02 15:03:31 -0700351 manager.v6Handler = v6Handler;
352
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700353 // properties
354 Dictionary<String, Object> dictionary = createNiceMock(Dictionary.class);
355 expect(dictionary.get("arpEnabled")).andReturn(true).anyTimes();
356 ComponentContext context = createNiceMock(ComponentContext.class);
357 expect(context.getProperties()).andReturn(dictionary).anyTimes();
358
Yi Tseng4025a102017-09-30 11:35:42 +0800359 replay(manager.cfgService, manager.coreService, manager.hostService,
360 manager.compCfgService, dictionary, context);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700361 manager.activate(context);
362 }
363
364 @After
365 public void tearDown() {
366 manager.deactivate();
367 }
368
369 /**
370 * Relay a DHCP packet without option 82.
371 * Should add new host to host store after dhcp ack.
372 */
373 @Test
374 public void relayDhcpWithoutAgentInfo() {
Yi Tsengaa417a62017-09-08 17:22:51 -0700375 replay(mockHostProviderService);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700376 // send request
377 packetService.processPacket(new TestDhcpRequestPacketContext(CLIENT_MAC,
378 CLIENT_VLAN,
379 CLIENT_CP,
380 INTERFACE_IP.ipAddress().getIp4Address(),
381 false));
Yi Tsengaa417a62017-09-08 17:22:51 -0700382 // won't trigger the host provider service
383 verify(mockHostProviderService);
384 reset(mockHostProviderService);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700385
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700386 assertEquals(0, mockRouteStore.routes.size());
387
Yi Tsengaa417a62017-09-08 17:22:51 -0700388 HostId expectHostId = HostId.hostId(CLIENT_MAC, CLIENT_VLAN);
389 Capture<HostDescription> capturedHostDesc = newCapture();
390 mockHostProviderService.hostDetected(eq(expectHostId), capture(capturedHostDesc), eq(false));
391 replay(mockHostProviderService);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700392 // send ack
393 packetService.processPacket(new TestDhcpAckPacketContext(CLIENT_CP, CLIENT_MAC,
394 CLIENT_VLAN, INTERFACE_IP.ipAddress().getIp4Address(),
395 false));
Yi Tsengaa417a62017-09-08 17:22:51 -0700396 verify(mockHostProviderService);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700397 assertEquals(0, mockRouteStore.routes.size());
398
Yi Tsengaa417a62017-09-08 17:22:51 -0700399 HostDescription host = capturedHostDesc.getValue();
400 assertEquals(false, host.configured());
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700401 assertEquals(CLIENT_CP.deviceId(), host.location().elementId());
402 assertEquals(CLIENT_CP.port(), host.location().port());
Yi Tsengaa417a62017-09-08 17:22:51 -0700403 assertEquals(1, host.ipAddress().size());
404 assertEquals(IP_FOR_CLIENT, host.ipAddress().iterator().next());
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700405 }
406
407 /**
408 * Relay a DHCP packet with option 82 (Indirectly connected host).
409 */
410 @Test
411 public void relayDhcpWithAgentInfo() {
Yi Tsengaa417a62017-09-08 17:22:51 -0700412 replay(mockHostProviderService);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700413 // Assume outer dhcp relay agent exists in store already
414 // send request
415 packetService.processPacket(new TestDhcpRequestPacketContext(CLIENT2_MAC,
416 CLIENT2_VLAN,
417 CLIENT2_CP,
418 INTERFACE_IP.ipAddress().getIp4Address(),
419 true));
Yi Tsengaa417a62017-09-08 17:22:51 -0700420 // No routes
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700421 assertEquals(0, mockRouteStore.routes.size());
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700422 // send ack
423 packetService.processPacket(new TestDhcpAckPacketContext(CLIENT2_CP,
424 CLIENT2_MAC,
425 CLIENT2_VLAN,
426 INTERFACE_IP.ipAddress().getIp4Address(),
427 true));
428
Yi Tsengaa417a62017-09-08 17:22:51 -0700429 // won't trigger the host provider service
430 verify(mockHostProviderService);
431 reset(mockHostProviderService);
432
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700433 assertEquals(1, mockRouteStore.routes.size());
434
435 Route route = mockRouteStore.routes.get(0);
436 assertEquals(OUTER_RELAY_IP, route.nextHop());
437 assertEquals(IP_FOR_CLIENT.toIpPrefix(), route.prefix());
438 assertEquals(Route.Source.STATIC, route.source());
439 }
440
441 @Test
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700442 public void testWithRelayAgentConfig() throws DeserializationException {
443 manager.v4Handler
444 .setDefaultDhcpServerConfigs(ImmutableList.of(new MockDhcpServerConfig(RELAY_AGENT_IP)));
Yi Tseng4f2a0462017-08-31 11:21:00 -0700445 manager.v4Handler
446 .setIndirectDhcpServerConfigs(ImmutableList.of(new MockDhcpServerConfig(RELAY_AGENT_IP)));
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700447 packetService.processPacket(new TestDhcpRequestPacketContext(CLIENT2_MAC,
448 CLIENT2_VLAN,
449 CLIENT2_CP,
450 INTERFACE_IP.ipAddress().getIp4Address(),
451 true));
452 OutboundPacket outPacket = packetService.emittedPacket;
453 byte[] outData = outPacket.data().array();
454 Ethernet eth = Ethernet.deserializer().deserialize(outData, 0, outData.length);
455 IPv4 ip = (IPv4) eth.getPayload();
456 UDP udp = (UDP) ip.getPayload();
457 DHCP dhcp = (DHCP) udp.getPayload();
458 assertEquals(RELAY_AGENT_IP.toInt(), dhcp.getGatewayIPAddress());
459 }
460
461 @Test
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700462 public void testArpRequest() throws Exception {
463 packetService.processPacket(new TestArpRequestPacketContext(CLIENT_INTERFACE));
Ray Milkeyc108a6b2017-08-23 15:23:50 -0700464 OutboundPacket outboundPacket = packetService.emittedPacket;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700465 byte[] outPacketData = outboundPacket.data().array();
466 Ethernet eth = Ethernet.deserializer().deserialize(outPacketData, 0, outPacketData.length);
467
468 assertEquals(eth.getEtherType(), Ethernet.TYPE_ARP);
469 ARP arp = (ARP) eth.getPayload();
470 assertArrayEquals(arp.getSenderHardwareAddress(), CLIENT_INTERFACE.mac().toBytes());
471 }
472
Yi Tseng51f1be92017-09-01 17:24:57 -0700473 /**
474 * Ignores specific vlans from specific devices if config.
475 *
476 * @throws Exception the exception from this test
477 */
478 @Test
479 public void testIgnoreVlan() throws Exception {
480 ObjectMapper om = new ObjectMapper();
481 JsonNode json = om.readTree(Resources.getResource(CONFIG_FILE_PATH));
482 IgnoreDhcpConfig config = new IgnoreDhcpConfig();
483 json = json.path("apps").path(DHCP_RELAY_APP).path(IgnoreDhcpConfig.KEY);
484 config.init(APP_ID, IgnoreDhcpConfig.KEY, json, om, null);
485
486 Capture<Objective> capturedFromDev1 = newCapture(CaptureType.ALL);
Yi Tseng525ff402017-10-23 19:39:39 -0700487 flowObjectiveService.apply(eq(DEV_1_ID), capture(capturedFromDev1));
Yi Tseng127ffe52017-09-12 15:55:17 -0700488 expectLastCall().times(DHCP_SELECTORS.size());
Yi Tseng51f1be92017-09-01 17:24:57 -0700489 Capture<Objective> capturedFromDev2 = newCapture(CaptureType.ALL);
Yi Tseng525ff402017-10-23 19:39:39 -0700490 flowObjectiveService.apply(eq(DEV_2_ID), capture(capturedFromDev2));
Yi Tseng127ffe52017-09-12 15:55:17 -0700491 expectLastCall().times(DHCP_SELECTORS.size());
Yi Tseng525ff402017-10-23 19:39:39 -0700492 replay(flowObjectiveService);
Yi Tseng51f1be92017-09-01 17:24:57 -0700493 manager.updateConfig(config);
Yi Tseng525ff402017-10-23 19:39:39 -0700494 verify(flowObjectiveService);
Yi Tseng51f1be92017-09-01 17:24:57 -0700495
496 List<Objective> objectivesFromDev1 = capturedFromDev1.getValues();
497 List<Objective> objectivesFromDev2 = capturedFromDev2.getValues();
498
499 assertTrue(objectivesFromDev1.containsAll(objectivesFromDev2));
500 assertTrue(objectivesFromDev2.containsAll(objectivesFromDev1));
Yi Tseng525ff402017-10-23 19:39:39 -0700501 TrafficTreatment dropTreatment = DefaultTrafficTreatment.builder().wipeDeferred().build();
Yi Tseng51f1be92017-09-01 17:24:57 -0700502
503 for (int index = 0; index < objectivesFromDev1.size(); index++) {
504 TrafficSelector selector =
Yi Tseng525ff402017-10-23 19:39:39 -0700505 DefaultTrafficSelector.builder(DHCP_SELECTORS.get(index))
Yi Tseng51f1be92017-09-01 17:24:57 -0700506 .matchVlanId(IGNORED_VLAN)
507 .build();
508 ForwardingObjective fwd = (ForwardingObjective) objectivesFromDev1.get(index);
509 assertEquals(selector, fwd.selector());
510 assertEquals(dropTreatment, fwd.treatment());
511 assertEquals(IGNORE_CONTROL_PRIORITY, fwd.priority());
512 assertEquals(ForwardingObjective.Flag.VERSATILE, fwd.flag());
513 assertEquals(Objective.Operation.ADD, fwd.op());
Yi Tseng127ffe52017-09-12 15:55:17 -0700514 fwd.context().ifPresent(ctx -> {
515 ctx.onSuccess(fwd);
516 });
Yi Tseng51f1be92017-09-01 17:24:57 -0700517 }
Yi Tseng127ffe52017-09-12 15:55:17 -0700518 objectivesFromDev2.forEach(obj -> obj.context().ifPresent(ctx -> ctx.onSuccess(obj)));
Yi Tseng525ff402017-10-23 19:39:39 -0700519 assertEquals(2, v4Handler.ignoredVlans.size());
520 assertEquals(2, v6Handler.ignoredVlans.size());
Yi Tseng51f1be92017-09-01 17:24:57 -0700521 }
522
523 /**
524 * "IgnoreVlan" policy should be removed when the config removed.
525 */
526 @Test
527 public void testRemoveIgnoreVlan() {
Yi Tseng525ff402017-10-23 19:39:39 -0700528 v4Handler.ignoredVlans.put(DEV_1_ID, IGNORED_VLAN);
529 v4Handler.ignoredVlans.put(DEV_2_ID, IGNORED_VLAN);
530 v6Handler.ignoredVlans.put(DEV_1_ID, IGNORED_VLAN);
531 v6Handler.ignoredVlans.put(DEV_2_ID, IGNORED_VLAN);
Yi Tseng51f1be92017-09-01 17:24:57 -0700532 IgnoreDhcpConfig config = new IgnoreDhcpConfig();
533
534 Capture<Objective> capturedFromDev1 = newCapture(CaptureType.ALL);
Yi Tseng525ff402017-10-23 19:39:39 -0700535 flowObjectiveService.apply(eq(DEV_1_ID), capture(capturedFromDev1));
Yi Tseng127ffe52017-09-12 15:55:17 -0700536 expectLastCall().times(DHCP_SELECTORS.size());
Yi Tseng51f1be92017-09-01 17:24:57 -0700537 Capture<Objective> capturedFromDev2 = newCapture(CaptureType.ALL);
Yi Tseng525ff402017-10-23 19:39:39 -0700538 flowObjectiveService.apply(eq(DEV_2_ID), capture(capturedFromDev2));
Yi Tseng127ffe52017-09-12 15:55:17 -0700539 expectLastCall().times(DHCP_SELECTORS.size());
Yi Tseng525ff402017-10-23 19:39:39 -0700540 replay(flowObjectiveService);
Yi Tseng51f1be92017-09-01 17:24:57 -0700541 manager.removeConfig(config);
Yi Tseng525ff402017-10-23 19:39:39 -0700542 verify(flowObjectiveService);
Yi Tseng51f1be92017-09-01 17:24:57 -0700543
544 List<Objective> objectivesFromDev1 = capturedFromDev1.getValues();
545 List<Objective> objectivesFromDev2 = capturedFromDev2.getValues();
546
547 assertTrue(objectivesFromDev1.containsAll(objectivesFromDev2));
548 assertTrue(objectivesFromDev2.containsAll(objectivesFromDev1));
Yi Tseng525ff402017-10-23 19:39:39 -0700549 TrafficTreatment dropTreatment = DefaultTrafficTreatment.builder().wipeDeferred().build();
Yi Tseng51f1be92017-09-01 17:24:57 -0700550
551 for (int index = 0; index < objectivesFromDev1.size(); index++) {
552 TrafficSelector selector =
Yi Tseng525ff402017-10-23 19:39:39 -0700553 DefaultTrafficSelector.builder(DHCP_SELECTORS.get(index))
Yi Tseng51f1be92017-09-01 17:24:57 -0700554 .matchVlanId(IGNORED_VLAN)
555 .build();
556 ForwardingObjective fwd = (ForwardingObjective) objectivesFromDev1.get(index);
557 assertEquals(selector, fwd.selector());
558 assertEquals(dropTreatment, fwd.treatment());
559 assertEquals(IGNORE_CONTROL_PRIORITY, fwd.priority());
560 assertEquals(ForwardingObjective.Flag.VERSATILE, fwd.flag());
561 assertEquals(Objective.Operation.REMOVE, fwd.op());
Yi Tseng127ffe52017-09-12 15:55:17 -0700562 fwd.context().ifPresent(ctx -> {
563 ctx.onSuccess(fwd);
564 });
Yi Tseng51f1be92017-09-01 17:24:57 -0700565 }
Yi Tseng127ffe52017-09-12 15:55:17 -0700566 objectivesFromDev2.forEach(obj -> obj.context().ifPresent(ctx -> ctx.onSuccess(obj)));
Yi Tseng525ff402017-10-23 19:39:39 -0700567 assertEquals(0, v4Handler.ignoredVlans.size());
568 assertEquals(0, v6Handler.ignoredVlans.size());
Yi Tseng51f1be92017-09-01 17:24:57 -0700569 }
570
Kalhee Kim45fede42017-09-05 19:05:06 +0000571 /**
Yi Tseng127ffe52017-09-12 15:55:17 -0700572 * Should ignore ignore rules installation when device not available.
573 */
574 @Test
575 public void testIgnoreUnknownDevice() throws IOException {
576 reset(manager.deviceService);
577 Device device = createNiceMock(Device.class);
578 expect(device.is(Pipeliner.class)).andReturn(true).anyTimes();
579
580 expect(manager.deviceService.getDevice(DEV_1_ID)).andReturn(device).anyTimes();
581 expect(manager.deviceService.getDevice(DEV_2_ID)).andReturn(null).anyTimes();
582
583 ObjectMapper om = new ObjectMapper();
584 JsonNode json = om.readTree(Resources.getResource(CONFIG_FILE_PATH));
585 IgnoreDhcpConfig config = new IgnoreDhcpConfig();
586 json = json.path("apps").path(DHCP_RELAY_APP).path(IgnoreDhcpConfig.KEY);
587 config.init(APP_ID, IgnoreDhcpConfig.KEY, json, om, null);
588
589 Capture<Objective> capturedFromDev1 = newCapture(CaptureType.ALL);
Yi Tseng525ff402017-10-23 19:39:39 -0700590 flowObjectiveService.apply(eq(DEV_1_ID), capture(capturedFromDev1));
Yi Tseng127ffe52017-09-12 15:55:17 -0700591 expectLastCall().times(DHCP_SELECTORS.size());
Yi Tseng525ff402017-10-23 19:39:39 -0700592 replay(flowObjectiveService, manager.deviceService, device);
Yi Tseng127ffe52017-09-12 15:55:17 -0700593
594 manager.updateConfig(config);
595 capturedFromDev1.getValues().forEach(obj -> obj.context().ifPresent(ctx -> ctx.onSuccess(obj)));
596
Yi Tseng525ff402017-10-23 19:39:39 -0700597 assertEquals(1, v4Handler.ignoredVlans.size());
598 assertEquals(1, v6Handler.ignoredVlans.size());
Yi Tseng127ffe52017-09-12 15:55:17 -0700599 }
600
601 /**
602 * Should try install ignore rules when device comes up.
603 */
604 @Test
605 public void testInstallIgnoreRuleWhenDeviceComesUp() throws IOException {
606 ObjectMapper om = new ObjectMapper();
607 JsonNode json = om.readTree(Resources.getResource(CONFIG_FILE_PATH));
608 IgnoreDhcpConfig config = new IgnoreDhcpConfig();
609 json = json.path("apps").path(DHCP_RELAY_APP).path(IgnoreDhcpConfig.KEY);
610 config.init(APP_ID, IgnoreDhcpConfig.KEY, json, om, null);
611
Yi Tseng525ff402017-10-23 19:39:39 -0700612 reset(manager.cfgService, flowObjectiveService, manager.deviceService);
Yi Tseng127ffe52017-09-12 15:55:17 -0700613 expect(manager.cfgService.getConfig(APP_ID, IgnoreDhcpConfig.class))
614 .andReturn(config).anyTimes();
615
616 Device device = createNiceMock(Device.class);
617 expect(device.is(Pipeliner.class)).andReturn(true).anyTimes();
618 expect(device.id()).andReturn(DEV_1_ID).anyTimes();
619 expect(manager.deviceService.getDevice(DEV_1_ID)).andReturn(device).anyTimes();
620 DeviceEvent event = new DeviceEvent(DeviceEvent.Type.DEVICE_ADDED, device);
621 Capture<Objective> capturedFromDev1 = newCapture(CaptureType.ALL);
Yi Tseng525ff402017-10-23 19:39:39 -0700622 flowObjectiveService.apply(eq(DEV_1_ID), capture(capturedFromDev1));
Yi Tseng127ffe52017-09-12 15:55:17 -0700623 expectLastCall().times(DHCP_SELECTORS.size());
Yi Tseng525ff402017-10-23 19:39:39 -0700624 replay(manager.cfgService, flowObjectiveService, manager.deviceService, device);
Yi Tseng127ffe52017-09-12 15:55:17 -0700625 manager.deviceListener.event(event);
626 capturedFromDev1.getValues().forEach(obj -> obj.context().ifPresent(ctx -> ctx.onSuccess(obj)));
Yi Tseng525ff402017-10-23 19:39:39 -0700627 assertEquals(1, v4Handler.ignoredVlans.size());
628 assertEquals(1, v6Handler.ignoredVlans.size());
Yi Tseng127ffe52017-09-12 15:55:17 -0700629 }
630
631 /**
Kalhee Kim45fede42017-09-05 19:05:06 +0000632 * Relay a DHCP6 packet without relay option
633 * Note: Should add new host to host store after dhcp ack.
634 */
635 @Test
636 public void relayDhcp6WithoutAgentInfo() {
Yi Tsengaa417a62017-09-08 17:22:51 -0700637 replay(mockHostProviderService);
Kalhee Kim45fede42017-09-05 19:05:06 +0000638 // send request
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000639 packetService.processPacket(new TestDhcp6RequestPacketContext(DHCP6.MsgType.REQUEST.value(),
640 CLIENT_MAC,
641 CLIENT_VLAN,
Kalhee Kim45fede42017-09-05 19:05:06 +0000642 CLIENT_CP,
643 INTERFACE_IP_V6.ipAddress().getIp6Address(),
644 0));
645
Yi Tsengaa417a62017-09-08 17:22:51 -0700646 verify(mockHostProviderService);
647 reset(mockHostProviderService);
Kalhee Kim45fede42017-09-05 19:05:06 +0000648 assertEquals(0, mockRouteStore.routes.size());
649
Yi Tsengaa417a62017-09-08 17:22:51 -0700650 Capture<HostDescription> capturedHostDesc = newCapture();
651 mockHostProviderService.hostDetected(eq(HostId.hostId(CLIENT_MAC, CLIENT_VLAN)),
652 capture(capturedHostDesc), eq(false));
653 replay(mockHostProviderService);
Kalhee Kim45fede42017-09-05 19:05:06 +0000654 // send reply
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000655 packetService.processPacket(new TestDhcp6ReplyPacketContext(DHCP6.MsgType.REPLY.value(),
656 CLIENT_CP, CLIENT_MAC,
Kalhee Kim45fede42017-09-05 19:05:06 +0000657 CLIENT_VLAN,
658 INTERFACE_IP_V6.ipAddress().getIp6Address(),
Kalhee Kim121ba922017-11-01 17:56:44 +0000659 0, false, CLIENT_VLAN));
Yi Tsengaa417a62017-09-08 17:22:51 -0700660 verify(mockHostProviderService);
Kalhee Kim45fede42017-09-05 19:05:06 +0000661 assertEquals(0, mockRouteStore.routes.size());
662
Yi Tsengaa417a62017-09-08 17:22:51 -0700663 HostDescription host = capturedHostDesc.getValue();
Kalhee Kim45fede42017-09-05 19:05:06 +0000664 assertEquals(CLIENT_VLAN, host.vlan());
665 assertEquals(CLIENT_CP.deviceId(), host.location().elementId());
666 assertEquals(CLIENT_CP.port(), host.location().port());
Yi Tsengaa417a62017-09-08 17:22:51 -0700667 assertEquals(1, host.ipAddress().size());
668 assertEquals(IP_FOR_CLIENT_V6, host.ipAddress().iterator().next());
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000669
670 // send release
671 packetService.processPacket(new TestDhcp6RequestPacketContext(DHCP6.MsgType.RELEASE.value(),
672 CLIENT_MAC,
673 CLIENT_VLAN,
674 CLIENT_CP,
675 INTERFACE_IP_V6.ipAddress().getIp6Address(),
676 0));
677
678 assertEquals(null, manager.hostService.getHost(HostId.hostId(CLIENT_MAC, CLIENT_VLAN)));
Kalhee Kim45fede42017-09-05 19:05:06 +0000679 }
680
681 /**
682 * Relay a DHCP6 packet with Relay Message opion (Indirectly connected host).
683 */
684 @Test
685 public void relayDhcp6WithAgentInfo() {
Yi Tsengaa417a62017-09-08 17:22:51 -0700686 replay(mockHostProviderService);
Kalhee Kim45fede42017-09-05 19:05:06 +0000687 // Assume outer dhcp6 relay agent exists in store already
688 // send request
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000689 packetService.processPacket(new TestDhcp6RequestPacketContext(DHCP6.MsgType.REQUEST.value(),
690 CLIENT2_MAC,
691 CLIENT2_VLAN,
692 CLIENT2_CP,
693 OUTER_RELAY_IP_V6,
694 1));
695
696 assertEquals(0, mockRouteStore.routes.size());
697
698 // send reply
699 packetService.processPacket(new TestDhcp6ReplyPacketContext(DHCP6.MsgType.REPLY.value(), CLIENT2_CP,
700 CLIENT2_MAC,
701 CLIENT2_VLAN,
702 OUTER_RELAY_IP_V6,
Kalhee Kim121ba922017-11-01 17:56:44 +0000703 1, false, CLIENT2_VLAN));
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000704
705 // won't trigger the host provider service
706 verify(mockHostProviderService);
707 reset(mockHostProviderService);
708 assertEquals(2, mockRouteStore.routes.size()); // ipAddress and prefix
709
710 Route aRoute = mockRouteStore.routes.stream()
711 .filter(rt -> rt.prefix().contains(IP_FOR_CLIENT_V6))
712 .findFirst()
713 .orElse(null);
714 assertNotEquals(null, aRoute);
715
716 aRoute = mockRouteStore.routes.stream()
717 .filter(rt -> rt.prefix().contains(PREFIX_FOR_CLIENT_V6))
718 .findFirst()
719 .orElse(null);
720 assertNotEquals(null, aRoute);
721
722 // send release msg
723 packetService.processPacket(new TestDhcp6RequestPacketContext(DHCP6.MsgType.RELEASE.value(),
724 CLIENT2_MAC,
725 CLIENT2_VLAN,
726 CLIENT2_CP,
727 OUTER_RELAY_IP_V6,
728 1));
729
730 aRoute = mockRouteStore.routes.stream()
731 .filter(rt -> rt.prefix().contains(IP_FOR_CLIENT_V6))
732 .findFirst()
733 .orElse(null);
734 assertEquals(null, aRoute);
735
736 aRoute = mockRouteStore.routes.stream()
737 .filter(rt -> rt.prefix().contains(PREFIX_FOR_CLIENT_V6))
738 .findFirst()
739 .orElse(null);
740 assertEquals(null, aRoute);
741
742 assertEquals(0, mockRouteStore.routes.size());
743
744 }
745
746 /**
747 * Relay a DHCP6 packet with Relay Message opion (Indirectly connected host) and server responded
748 * with vlan differnt from client interface vlan.
749 */
750 @Test
751 public void relayDhcp6WithAgentInfoWrongVlan() {
752 replay(mockHostProviderService);
753 // Assume outer dhcp6 relay agent exists in store already
754 // send request
755 packetService.processPacket(new TestDhcp6RequestPacketContext(DHCP6.MsgType.REQUEST.value(),
756 CLIENT2_MAC,
Kalhee Kim45fede42017-09-05 19:05:06 +0000757 CLIENT2_VLAN,
758 CLIENT2_CP,
759 INTERFACE_IP_V6.ipAddress().getIp6Address(),
760 1));
761
Kalhee Kim45fede42017-09-05 19:05:06 +0000762 assertEquals(0, mockRouteStore.routes.size());
763
764 // send reply
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000765 packetService.processPacket(new TestDhcp6ReplyPacketContext(DHCP6.MsgType.REPLY.value(),
766 CLIENT2_CP,
Kalhee Kim45fede42017-09-05 19:05:06 +0000767 CLIENT2_MAC,
Kalhee Kim121ba922017-11-01 17:56:44 +0000768 CLIENT2_VLAN,
Kalhee Kim45fede42017-09-05 19:05:06 +0000769 INTERFACE_IP_V6.ipAddress().getIp6Address(),
Kalhee Kim121ba922017-11-01 17:56:44 +0000770 1, true,
771 CLIENT_BOGUS_VLAN // mismatch
772 ));
Kalhee Kim45fede42017-09-05 19:05:06 +0000773
Yi Tsengaa417a62017-09-08 17:22:51 -0700774 // won't trigger the host provider service
775 verify(mockHostProviderService);
776 reset(mockHostProviderService);
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000777 assertEquals(0, mockRouteStore.routes.size()); // ipAddress and prefix
Kalhee Kim45fede42017-09-05 19:05:06 +0000778
Kalhee Kim45fede42017-09-05 19:05:06 +0000779 }
Yi Tsengaa417a62017-09-08 17:22:51 -0700780
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000781
Yi Tsengaa417a62017-09-08 17:22:51 -0700782 @Test
783 public void testDhcp4DualHome() {
784 PacketContext packetContext =
785 new TestDhcpAckPacketContext(CLIENT_DH_CP, CLIENT_MAC, CLIENT_VLAN,
786 INTERFACE_IP.ipAddress().getIp4Address(),
787 false);
788 reset(manager.hostService);
789 expect(manager.hostService.getHost(CLIENT_HOST_ID)).andReturn(EXISTS_HOST).anyTimes();
790 Capture<HostDescription> capturedHostDesc = newCapture();
791 mockHostProviderService.hostDetected(eq(CLIENT_HOST_ID), capture(capturedHostDesc), eq(false));
792 replay(mockHostProviderService, manager.hostService);
793 packetService.processPacket(packetContext);
794 verify(mockHostProviderService);
795
796 HostDescription hostDesc = capturedHostDesc.getValue();
797 Set<HostLocation> hostLocations = hostDesc.locations();
798 assertEquals(2, hostLocations.size());
799 assertTrue(hostLocations.contains(CLIENT_LOCATION));
800 assertTrue(hostLocations.contains(CLIENT_DH_LOCATION));
801 }
802
803 @Test
804 public void testDhcp6DualHome() {
805 PacketContext packetContext =
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000806 new TestDhcp6ReplyPacketContext(DHCP6.MsgType.REPLY.value(),
807 CLIENT_DH_CP, CLIENT_MAC, CLIENT_VLAN,
Yi Tsengaa417a62017-09-08 17:22:51 -0700808 INTERFACE_IP_V6.ipAddress().getIp6Address(),
Kalhee Kim121ba922017-11-01 17:56:44 +0000809 0, false, CLIENT_VLAN);
Yi Tsengaa417a62017-09-08 17:22:51 -0700810 reset(manager.hostService);
811 expect(manager.hostService.getHostsByIp(CLIENT_LL_IP_V6)).andReturn(ImmutableSet.of(EXISTS_HOST)).anyTimes();
812
813 // FIXME: currently DHCPv6 has a bug, we can't get correct vlan of client......
814 // XXX: The vlan relied from DHCP6 handler might be wrong, do hack here
815 HostId hostId = HostId.hostId(CLIENT_MAC, VlanId.NONE);
816 expect(manager.hostService.getHost(hostId)).andReturn(EXISTS_HOST).anyTimes();
817
818 // XXX: sometimes this will work, sometimes not
819 expect(manager.hostService.getHost(CLIENT_HOST_ID)).andReturn(EXISTS_HOST).anyTimes();
820
821 Capture<HostDescription> capturedHostDesc = newCapture();
822
823 // XXX: also a hack here
824 mockHostProviderService.hostDetected(eq(hostId), capture(capturedHostDesc), eq(false));
825 expectLastCall().anyTimes();
826
827 mockHostProviderService.hostDetected(eq(CLIENT_HOST_ID), capture(capturedHostDesc), eq(false));
828 expectLastCall().anyTimes();
829 replay(mockHostProviderService, manager.hostService);
830 packetService.processPacket(packetContext);
831 verify(mockHostProviderService);
832
833 HostDescription hostDesc = capturedHostDesc.getValue();
834 Set<HostLocation> hostLocations = hostDesc.locations();
835 assertEquals(2, hostLocations.size());
836 assertTrue(hostLocations.contains(CLIENT_LOCATION));
837 assertTrue(hostLocations.contains(CLIENT_DH_LOCATION));
838 }
839
Yi Tseng483ac6f2017-08-02 15:03:31 -0700840 private static class MockDefaultDhcpRelayConfig extends DefaultDhcpRelayConfig {
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700841 @Override
842 public boolean isValid() {
843 return true;
844 }
845
846 @Override
Yi Tseng483ac6f2017-08-02 15:03:31 -0700847 public List<DhcpServerConfig> dhcpServerConfigs() {
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700848 return ImmutableList.of(new MockDhcpServerConfig(null));
Yi Tseng483ac6f2017-08-02 15:03:31 -0700849 }
850 }
851
Kalhee Kim45fede42017-09-05 19:05:06 +0000852 private static class MockIndirectDhcpRelayConfig extends IndirectDhcpRelayConfig {
853 @Override
854 public boolean isValid() {
855 return true;
856 }
857
858 @Override
859 public List<DhcpServerConfig> dhcpServerConfigs() {
860 return ImmutableList.of(new MockDhcpServerConfig(null));
861 }
862 }
863
Yi Tseng483ac6f2017-08-02 15:03:31 -0700864 private static class MockDhcpServerConfig extends DhcpServerConfig {
Yi Tseng3df7f9d2017-08-17 13:08:31 -0700865 Ip4Address relayAgentIp;
866
867 /**
868 * Create mocked version DHCP server config.
869 *
870 * @param relayAgentIp the relay agent Ip config; null if we don't need it
871 */
872 public MockDhcpServerConfig(Ip4Address relayAgentIp) {
873 this.relayAgentIp = relayAgentIp;
874 }
875
876 @Override
877 public Optional<Ip4Address> getRelayAgentIp4() {
878 return Optional.ofNullable(relayAgentIp);
879 }
880
Yi Tseng483ac6f2017-08-02 15:03:31 -0700881 @Override
882 public Optional<ConnectPoint> getDhcpServerConnectPoint() {
883 return Optional.of(SERVER_CONNECT_POINT);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700884 }
885
Yi Tseng483ac6f2017-08-02 15:03:31 -0700886 @Override
887 public Optional<Ip4Address> getDhcpServerIp4() {
888 return Optional.of(SERVER_IP);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700889 }
Kalhee Kim45fede42017-09-05 19:05:06 +0000890
891 @Override
892 public Optional<Ip4Address> getDhcpGatewayIp4() {
893 return Optional.of(GATEWAY_IP);
894 }
895
896 @Override
897 public Optional<Ip6Address> getDhcpServerIp6() {
898 return Optional.of(SERVER_IP_V6);
899 }
900
901 @Override
902 public Optional<Ip6Address> getDhcpGatewayIp6() {
903 return Optional.of(GATEWAY_IP_V6);
904 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700905 }
906
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700907 private class MockRouteStore extends RouteStoreAdapter {
908 private List<Route> routes = Lists.newArrayList();
909
910 @Override
911 public void updateRoute(Route route) {
912 routes.add(route);
913 }
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +0000914
915 @Override
916 public void removeRoute(Route route) {
917 routes.remove(route);
918 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700919 }
920
921 private class MockInterfaceService extends InterfaceServiceAdapter {
922
923 @Override
924 public Set<Interface> getInterfaces() {
925 return INTERFACES;
926 }
927
928 @Override
929 public Set<Interface> getInterfacesByIp(IpAddress ip) {
930 return INTERFACES.stream()
931 .filter(iface -> {
932 return iface.ipAddressesList().stream()
933 .anyMatch(ifaceIp -> ifaceIp.ipAddress().equals(ip));
934 })
935 .collect(Collectors.toSet());
936 }
937
938 @Override
939 public Set<Interface> getInterfacesByPort(ConnectPoint port) {
940 return INTERFACES.stream()
941 .filter(iface -> iface.connectPoint().equals(port))
942 .collect(Collectors.toSet());
943 }
944 }
945
946 private class MockDhcpRelayStore implements DhcpRelayStore {
947 StoreDelegate<DhcpRelayStoreEvent> delegate;
948 private Map<HostId, DhcpRecord> records = Maps.newHashMap();
949
950 @Override
951 public void updateDhcpRecord(HostId hostId, DhcpRecord dhcpRecord) {
952 records.put(hostId, dhcpRecord);
953 DhcpRelayStoreEvent event = new DhcpRelayStoreEvent(DhcpRelayStoreEvent.Type.UPDATED,
954 dhcpRecord);
955 if (delegate != null) {
956 delegate.notify(event);
957 }
958 }
959
960 @Override
961 public Optional<DhcpRecord> getDhcpRecord(HostId hostId) {
962 return Optional.ofNullable(records.get(hostId));
963 }
964
965 @Override
966 public Collection<DhcpRecord> getDhcpRecords() {
967 return records.values();
968 }
969
970 @Override
971 public Optional<DhcpRecord> removeDhcpRecord(HostId hostId) {
972 DhcpRecord dhcpRecord = records.remove(hostId);
973 if (dhcpRecord != null) {
974 DhcpRelayStoreEvent event = new DhcpRelayStoreEvent(DhcpRelayStoreEvent.Type.REMOVED,
975 dhcpRecord);
976 if (delegate != null) {
977 delegate.notify(event);
978 }
979 }
980 return Optional.ofNullable(dhcpRecord);
981 }
982
983 @Override
984 public void setDelegate(StoreDelegate<DhcpRelayStoreEvent> delegate) {
985 this.delegate = delegate;
986 }
987
988 @Override
989 public void unsetDelegate(StoreDelegate<DhcpRelayStoreEvent> delegate) {
990 this.delegate = null;
991 }
992
993 @Override
994 public boolean hasDelegate() {
995 return this.delegate != null;
996 }
997 }
998
999 private class MockPacketService extends PacketServiceAdapter {
1000 Set<PacketProcessor> packetProcessors = Sets.newHashSet();
Ray Milkeyc108a6b2017-08-23 15:23:50 -07001001 OutboundPacket emittedPacket;
Yi Tseng7a38f9a2017-06-09 14:36:40 -07001002
1003 @Override
1004 public void addProcessor(PacketProcessor processor, int priority) {
1005 packetProcessors.add(processor);
1006 }
1007
1008 public void processPacket(PacketContext packetContext) {
1009 packetProcessors.forEach(p -> p.process(packetContext));
1010 }
1011
1012 @Override
1013 public void emit(OutboundPacket packet) {
Ray Milkeyc108a6b2017-08-23 15:23:50 -07001014 this.emittedPacket = packet;
Yi Tseng7a38f9a2017-06-09 14:36:40 -07001015 }
1016 }
1017
1018
1019
1020 /**
1021 * Generates DHCP REQUEST packet.
1022 */
1023 private class TestDhcpRequestPacketContext extends PacketContextAdapter {
1024
1025
1026 private InboundPacket inPacket;
1027
1028 public TestDhcpRequestPacketContext(MacAddress clientMac, VlanId vlanId,
1029 ConnectPoint clientCp,
1030 Ip4Address clientGwAddr,
1031 boolean withNonOnosRelayInfo) {
1032 super(0, null, null, false);
1033 byte[] dhcpMsgType = new byte[1];
1034 dhcpMsgType[0] = (byte) DHCP.MsgType.DHCPREQUEST.getValue();
1035
1036 DhcpOption dhcpOption = new DhcpOption();
1037 dhcpOption.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue());
1038 dhcpOption.setData(dhcpMsgType);
1039 dhcpOption.setLength((byte) 1);
1040 DhcpOption endOption = new DhcpOption();
1041 endOption.setCode(DHCP.DHCPOptionCode.OptionCode_END.getValue());
1042
1043 DHCP dhcp = new DHCP();
1044 dhcp.setHardwareType(DHCP.HWTYPE_ETHERNET);
1045 dhcp.setHardwareAddressLength((byte) 6);
1046 dhcp.setClientHardwareAddress(clientMac.toBytes());
1047 if (withNonOnosRelayInfo) {
1048 DhcpRelayAgentOption relayOption = new DhcpRelayAgentOption();
1049 DhcpOption circuitIdOption = new DhcpOption();
1050 CircuitId circuitId = new CircuitId("Custom option", VlanId.NONE);
1051 byte[] cid = circuitId.serialize();
1052 circuitIdOption.setCode(DhcpRelayAgentOption.RelayAgentInfoOptions.CIRCUIT_ID.getValue());
1053 circuitIdOption.setLength((byte) cid.length);
1054 circuitIdOption.setData(cid);
1055 relayOption.setCode(DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue());
1056 relayOption.addSubOption(circuitIdOption);
1057 dhcp.setOptions(ImmutableList.of(dhcpOption, relayOption, endOption));
1058 dhcp.setGatewayIPAddress(OUTER_RELAY_IP.getIp4Address().toInt());
1059 } else {
1060 dhcp.setOptions(ImmutableList.of(dhcpOption, endOption));
1061 }
1062
1063
1064 UDP udp = new UDP();
1065 udp.setPayload(dhcp);
1066 udp.setSourcePort(UDP.DHCP_CLIENT_PORT);
1067 udp.setDestinationPort(UDP.DHCP_SERVER_PORT);
1068
1069 IPv4 ipv4 = new IPv4();
1070 ipv4.setPayload(udp);
1071 ipv4.setDestinationAddress(SERVER_IP.toInt());
1072 ipv4.setSourceAddress(clientGwAddr.toInt());
1073
1074 Ethernet eth = new Ethernet();
1075 if (withNonOnosRelayInfo) {
1076 eth.setEtherType(Ethernet.TYPE_IPV4)
1077 .setVlanID(vlanId.toShort())
1078 .setSourceMACAddress(OUTER_RELAY_MAC)
1079 .setDestinationMACAddress(MacAddress.BROADCAST)
1080 .setPayload(ipv4);
1081 } else {
1082 eth.setEtherType(Ethernet.TYPE_IPV4)
1083 .setVlanID(vlanId.toShort())
1084 .setSourceMACAddress(clientMac)
1085 .setDestinationMACAddress(MacAddress.BROADCAST)
1086 .setPayload(ipv4);
1087 }
1088
1089 this.inPacket = new DefaultInboundPacket(clientCp, eth,
1090 ByteBuffer.wrap(eth.serialize()));
1091 }
1092
1093 @Override
1094 public InboundPacket inPacket() {
1095 return this.inPacket;
1096 }
1097 }
1098
1099 /**
1100 * Generates DHCP ACK packet.
1101 */
1102 private class TestDhcpAckPacketContext extends PacketContextAdapter {
1103 private InboundPacket inPacket;
1104
1105 public TestDhcpAckPacketContext(ConnectPoint clientCp, MacAddress clientMac,
1106 VlanId clientVlan, Ip4Address clientGwAddr,
1107 boolean withNonOnosRelayInfo) {
1108 super(0, null, null, false);
1109
1110 byte[] dhcpMsgType = new byte[1];
1111 dhcpMsgType[0] = (byte) DHCP.MsgType.DHCPACK.getValue();
1112
1113 DhcpOption dhcpOption = new DhcpOption();
1114 dhcpOption.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue());
1115 dhcpOption.setData(dhcpMsgType);
1116 dhcpOption.setLength((byte) 1);
1117
1118 DhcpOption endOption = new DhcpOption();
1119 endOption.setCode(DHCP.DHCPOptionCode.OptionCode_END.getValue());
1120
1121 DHCP dhcp = new DHCP();
1122 if (withNonOnosRelayInfo) {
1123 DhcpRelayAgentOption relayOption = new DhcpRelayAgentOption();
1124 DhcpOption circuitIdOption = new DhcpOption();
Yi Tseng440e2b72017-08-24 14:47:34 -07001125 String circuitId = NON_ONOS_CID;
1126 byte[] cid = circuitId.getBytes(Charsets.US_ASCII);
Yi Tseng7a38f9a2017-06-09 14:36:40 -07001127 circuitIdOption.setCode(DhcpRelayAgentOption.RelayAgentInfoOptions.CIRCUIT_ID.getValue());
1128 circuitIdOption.setLength((byte) cid.length);
1129 circuitIdOption.setData(cid);
1130 relayOption.setCode(DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue());
1131 relayOption.addSubOption(circuitIdOption);
1132 dhcp.setOptions(ImmutableList.of(dhcpOption, relayOption, endOption));
1133 dhcp.setGatewayIPAddress(OUTER_RELAY_IP.getIp4Address().toInt());
1134 } else {
1135 CircuitId cid = new CircuitId(clientCp.toString(), clientVlan);
1136 byte[] circuitId = cid.serialize();
1137 DhcpOption circuitIdSubOption = new DhcpOption();
1138 circuitIdSubOption.setCode(DhcpRelayAgentOption.RelayAgentInfoOptions.CIRCUIT_ID.getValue());
1139 circuitIdSubOption.setData(circuitId);
1140 circuitIdSubOption.setLength((byte) circuitId.length);
1141
1142 DhcpRelayAgentOption relayInfoOption = new DhcpRelayAgentOption();
1143 relayInfoOption.setCode(DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue());
1144 relayInfoOption.addSubOption(circuitIdSubOption);
1145 dhcp.setOptions(ImmutableList.of(dhcpOption, relayInfoOption, endOption));
1146 dhcp.setGatewayIPAddress(clientGwAddr.toInt());
1147 }
1148 dhcp.setHardwareType(DHCP.HWTYPE_ETHERNET);
1149 dhcp.setHardwareAddressLength((byte) 6);
1150 dhcp.setClientHardwareAddress(clientMac.toBytes());
1151 dhcp.setYourIPAddress(IP_FOR_CLIENT.toInt());
1152
1153 UDP udp = new UDP();
1154 udp.setPayload(dhcp);
1155 udp.setSourcePort(UDP.DHCP_SERVER_PORT);
1156 udp.setDestinationPort(UDP.DHCP_CLIENT_PORT);
1157 IPv4 ipv4 = new IPv4();
1158 ipv4.setPayload(udp);
1159 ipv4.setDestinationAddress(IP_FOR_CLIENT.toString());
1160 ipv4.setSourceAddress(SERVER_IP.toString());
1161 Ethernet eth = new Ethernet();
1162 if (withNonOnosRelayInfo) {
1163 eth.setEtherType(Ethernet.TYPE_IPV4)
1164 .setVlanID(SERVER_VLAN.toShort())
1165 .setSourceMACAddress(SERVER_MAC)
1166 .setDestinationMACAddress(OUTER_RELAY_MAC)
1167 .setPayload(ipv4);
1168 } else {
1169 eth.setEtherType(Ethernet.TYPE_IPV4)
1170 .setVlanID(SERVER_VLAN.toShort())
1171 .setSourceMACAddress(SERVER_MAC)
1172 .setDestinationMACAddress(CLIENT_MAC)
1173 .setPayload(ipv4);
1174 }
1175
1176 this.inPacket = new DefaultInboundPacket(SERVER_CONNECT_POINT, eth,
1177 ByteBuffer.wrap(eth.serialize()));
1178
1179 }
1180
1181 @Override
1182 public InboundPacket inPacket() {
1183 return this.inPacket;
1184 }
1185 }
1186
1187 private class TestArpRequestPacketContext extends PacketContextAdapter {
1188 private InboundPacket inPacket;
1189
1190 public TestArpRequestPacketContext(Interface fromInterface) {
1191 super(0, null, null, false);
1192 ARP arp = new ARP();
1193 arp.setOpCode(ARP.OP_REQUEST);
1194
1195 IpAddress targetIp = fromInterface.ipAddressesList().get(0).ipAddress();
1196 arp.setTargetProtocolAddress(targetIp.toOctets());
1197 arp.setTargetHardwareAddress(MacAddress.BROADCAST.toBytes());
1198 arp.setSenderHardwareAddress(MacAddress.NONE.toBytes());
1199 arp.setSenderProtocolAddress(Ip4Address.valueOf(0).toOctets());
1200 arp.setHardwareAddressLength((byte) MacAddress.MAC_ADDRESS_LENGTH);
1201 Ethernet eth = new Ethernet();
1202 eth.setEtherType(Ethernet.TYPE_ARP);
1203 eth.setSourceMACAddress(MacAddress.NONE);
1204 eth.setDestinationMACAddress(MacAddress.BROADCAST);
1205 eth.setVlanID(fromInterface.vlan().toShort());
1206 eth.setPayload(arp);
1207
1208 this.inPacket = new DefaultInboundPacket(fromInterface.connectPoint(), eth,
1209 ByteBuffer.wrap(eth.serialize()));
1210 }
1211
1212 @Override
1213 public InboundPacket inPacket() {
1214 return this.inPacket;
1215 }
1216 }
Kalhee Kim45fede42017-09-05 19:05:06 +00001217
1218 /**
1219 * Generates DHCP6 REQUEST packet.
1220 */
1221 private void buildDhcp6Packet(DHCP6 dhcp6, byte msgType, Ip6Address ip6Addr, IpPrefix prefix) {
1222
1223 // build address option
1224 Dhcp6IaAddressOption iaAddressOption = new Dhcp6IaAddressOption();
1225 iaAddressOption.setCode(DHCP6.OptionCode.IAADDR.value());
1226 iaAddressOption.setIp6Address(ip6Addr);
1227 iaAddressOption.setPreferredLifetime(3600);
1228 iaAddressOption.setValidLifetime(1200);
1229 iaAddressOption.setLength((short) Dhcp6IaAddressOption.DEFAULT_LEN);
1230
1231 Dhcp6IaNaOption iaNaOption = new Dhcp6IaNaOption();
1232 iaNaOption.setCode(DHCP6.OptionCode.IA_NA.value());
1233 iaNaOption.setIaId(0);
1234 iaNaOption.setT1(302400);
1235 iaNaOption.setT2(483840);
1236 List<Dhcp6Option> iaNaSubOptions = new ArrayList<Dhcp6Option>();
1237 iaNaSubOptions.add(iaAddressOption);
1238 iaNaOption.setOptions(iaNaSubOptions);
1239 iaNaOption.setLength((short) (Dhcp6IaNaOption.DEFAULT_LEN + iaAddressOption.getLength()));
1240
1241 // build prefix option
1242 Dhcp6IaPrefixOption iaPrefixOption = new Dhcp6IaPrefixOption();
1243 iaPrefixOption.setCode(DHCP6.OptionCode.IAPREFIX.value());
1244 iaPrefixOption.setIp6Prefix(prefix.address().getIp6Address());
1245 iaPrefixOption.setPrefixLength((byte) prefix.prefixLength());
1246 iaPrefixOption.setPreferredLifetime(3601);
1247 iaPrefixOption.setValidLifetime(1201);
1248 iaPrefixOption.setLength((short) Dhcp6IaPrefixOption.DEFAULT_LEN);
1249
1250 Dhcp6IaPdOption iaPdOption = new Dhcp6IaPdOption();
1251 iaPdOption.setCode(DHCP6.OptionCode.IA_PD.value());
1252 iaPdOption.setIaId(0);
1253 iaPdOption.setT1(302401);
1254 iaPdOption.setT2(483841);
1255 List<Dhcp6Option> iaPdSubOptions = new ArrayList<Dhcp6Option>();
1256 iaPdSubOptions.add(iaPrefixOption);
1257 iaPdOption.setOptions(iaPdSubOptions);
1258 iaPdOption.setLength((short) (Dhcp6IaPdOption.DEFAULT_LEN + iaPrefixOption.getLength()));
1259
1260 dhcp6.setMsgType(msgType);
1261 List<Dhcp6Option> dhcp6Options = new ArrayList<Dhcp6Option>();
1262 dhcp6Options.add(iaNaOption);
1263 dhcp6Options.add(iaPdOption);
1264 dhcp6.setOptions(dhcp6Options);
1265
1266 }
1267
1268 private void buildRelayMsg(DHCP6 dhcp6Relay, byte msgType, Ip6Address linkAddr,
1269 Ip6Address peerAddr, byte hop, byte[] interfaceIdBytes,
1270 DHCP6 dhcp6Payload) {
1271
1272 dhcp6Relay.setMsgType(msgType);
1273
1274 dhcp6Relay.setLinkAddress(linkAddr.toOctets());
1275 dhcp6Relay.setPeerAddress(peerAddr.toOctets());
1276 dhcp6Relay.setHopCount(hop);
1277 List<Dhcp6Option> options = new ArrayList<Dhcp6Option>();
1278
1279 // interfaceId option
1280 Dhcp6Option interfaceId = new Dhcp6Option();
1281 interfaceId.setCode(DHCP6.OptionCode.INTERFACE_ID.value());
1282
1283
1284 interfaceId.setData(interfaceIdBytes);
1285 interfaceId.setLength((short) interfaceIdBytes.length);
1286 Dhcp6InterfaceIdOption interfaceIdOption = new Dhcp6InterfaceIdOption(interfaceId);
Kalhee Kima0b8f652017-10-18 22:00:30 +00001287 byte[] optionData = interfaceIdOption.getData();
Kalhee Kim45fede42017-09-05 19:05:06 +00001288 ByteBuffer bb = ByteBuffer.wrap(interfaceIdBytes);
1289
1290 byte[] macAddr = new byte[MacAddress.MAC_ADDRESS_LENGTH];
Kalhee Kima0b8f652017-10-18 22:00:30 +00001291 byte[] port = new byte[optionData.length - MacAddress.MAC_ADDRESS_LENGTH -
1292 VLAN_LEN - SEPARATOR_LEN * 2];
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001293 short vlan;
Kalhee Kim45fede42017-09-05 19:05:06 +00001294 bb.get(macAddr);
1295 bb.get(); // separator
1296 bb.get(port);
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001297 bb.get(); // separator
1298 vlan = bb.getShort();
Kalhee Kim45fede42017-09-05 19:05:06 +00001299 interfaceIdOption.setMacAddress(MacAddress.valueOf(macAddr));
1300 interfaceIdOption.setInPort(port);
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001301 interfaceIdOption.setVlanId(vlan);
Kalhee Kim45fede42017-09-05 19:05:06 +00001302
1303 options.add(interfaceIdOption);
1304
1305 // relay message option
1306 Dhcp6Option relayMsgOption = new Dhcp6Option();
1307 relayMsgOption.setCode(DHCP6.OptionCode.RELAY_MSG.value());
1308 byte[] dhcp6PayloadByte = dhcp6Payload.serialize();
1309 relayMsgOption.setLength((short) dhcp6PayloadByte.length);
1310 relayMsgOption.setPayload(dhcp6Payload);
1311 Dhcp6RelayOption relayOpt = new Dhcp6RelayOption(relayMsgOption);
1312
1313 options.add(relayOpt);
1314
1315 dhcp6Relay.setOptions(options);
1316 }
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001317 private byte[] buildInterfaceId(MacAddress clientMac, short vlanId, ConnectPoint clientCp) {
1318 String inPortString = "-" + clientCp.toString() + ":";
Kalhee Kim45fede42017-09-05 19:05:06 +00001319 byte[] clientSoureMacBytes = clientMac.toBytes();
1320 byte[] inPortStringBytes = inPortString.getBytes();
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001321 byte[] vlanIdBytes = new byte[2];
1322 vlanIdBytes[0] = (byte) ((vlanId >> 8) & 0xff); // high-order byte first
1323 vlanIdBytes[1] = (byte) (vlanId & 0xff);
1324 byte[] interfaceIdBytes = new byte[clientSoureMacBytes.length + inPortStringBytes.length + vlanIdBytes.length];
Kalhee Kim45fede42017-09-05 19:05:06 +00001325
1326 System.arraycopy(clientSoureMacBytes, 0, interfaceIdBytes, 0, clientSoureMacBytes.length);
1327 System.arraycopy(inPortStringBytes, 0, interfaceIdBytes, clientSoureMacBytes.length, inPortStringBytes.length);
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001328 System.arraycopy(vlanIdBytes, 0, interfaceIdBytes, clientSoureMacBytes.length + inPortStringBytes.length,
1329 vlanIdBytes.length);
Kalhee Kim45fede42017-09-05 19:05:06 +00001330
1331 return interfaceIdBytes;
1332 }
1333
Yi Tseng525ff402017-10-23 19:39:39 -07001334 private static List<TrafficSelector> buildClientDhcpSelectors() {
1335 return Streams.concat(Dhcp4HandlerImpl.DHCP_SELECTORS.stream(),
1336 Dhcp6HandlerImpl.DHCP_SELECTORS.stream())
1337 .collect(Collectors.toList());
1338 }
1339
Kalhee Kim45fede42017-09-05 19:05:06 +00001340 private class TestDhcp6RequestPacketContext extends PacketContextAdapter {
1341
1342
1343 private InboundPacket inPacket;
1344
1345
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001346 public TestDhcp6RequestPacketContext(byte msgType, MacAddress clientMac, VlanId vlanId,
Kalhee Kim45fede42017-09-05 19:05:06 +00001347 ConnectPoint clientCp,
1348 Ip6Address clientGwAddr,
1349 int relayLevel) {
1350 super(0, null, null, false);
1351
1352 DHCP6 dhcp6 = new DHCP6();
1353 if (relayLevel > 0) {
1354 DHCP6 dhcp6Payload = new DHCP6();
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001355 buildDhcp6Packet(dhcp6Payload, msgType,
Kalhee Kim45fede42017-09-05 19:05:06 +00001356 IP_FOR_CLIENT_V6,
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001357 msgType == DHCP6.MsgType.REQUEST.value() ? PREFIX_FOR_ZERO : PREFIX_FOR_CLIENT_V6);
Kalhee Kim45fede42017-09-05 19:05:06 +00001358 DHCP6 dhcp6Parent = null;
1359 DHCP6 dhcp6Child = dhcp6Payload;
1360 for (int i = 0; i < relayLevel; i++) {
1361 dhcp6Parent = new DHCP6();
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001362 byte[] interfaceId = buildInterfaceId(clientMac, vlanId.toShort(), clientCp);
Kalhee Kim45fede42017-09-05 19:05:06 +00001363 buildRelayMsg(dhcp6Parent, DHCP6.MsgType.RELAY_FORW.value(),
1364 INTERFACE_IP_V6.ipAddress().getIp6Address(),
1365 OUTER_RELAY_IP_V6,
1366 (byte) (relayLevel - 1), interfaceId,
1367 dhcp6Child);
1368 dhcp6Child = dhcp6Parent;
1369 }
1370 if (dhcp6Parent != null) {
1371 dhcp6 = dhcp6Parent;
1372 }
1373 } else {
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001374 buildDhcp6Packet(dhcp6, msgType,
Kalhee Kim45fede42017-09-05 19:05:06 +00001375 IP_FOR_CLIENT_V6,
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001376 msgType == DHCP6.MsgType.REQUEST.value() ? PREFIX_FOR_ZERO : PREFIX_FOR_CLIENT_V6);
Kalhee Kim45fede42017-09-05 19:05:06 +00001377 }
1378
1379 UDP udp = new UDP();
1380 udp.setPayload(dhcp6);
1381 if (relayLevel > 0) {
1382 udp.setSourcePort(UDP.DHCP_V6_SERVER_PORT);
1383 } else {
1384 udp.setSourcePort(UDP.DHCP_V6_CLIENT_PORT);
1385 }
1386 udp.setDestinationPort(UDP.DHCP_V6_SERVER_PORT);
1387
1388 IPv6 ipv6 = new IPv6();
1389 ipv6.setPayload(udp);
1390 ipv6.setNextHeader(IPv6.PROTOCOL_UDP);
1391 ipv6.setDestinationAddress(SERVER_IP_V6_MCAST.toOctets());
1392 ipv6.setSourceAddress(clientGwAddr.toOctets());
1393
1394 Ethernet eth = new Ethernet();
1395 if (relayLevel > 0) {
1396 eth.setEtherType(Ethernet.TYPE_IPV6)
Kalhee Kim121ba922017-11-01 17:56:44 +00001397 .setVlanID(OUTER_RELAY_VLAN.toShort())
Kalhee Kim45fede42017-09-05 19:05:06 +00001398 .setSourceMACAddress(OUTER_RELAY_MAC)
1399 .setDestinationMACAddress(MacAddress.valueOf("33:33:00:01:00:02"))
1400 .setPayload(ipv6);
1401 } else {
1402 eth.setEtherType(Ethernet.TYPE_IPV6)
1403 .setVlanID(vlanId.toShort())
1404 .setSourceMACAddress(clientMac)
1405 .setDestinationMACAddress(MacAddress.valueOf("33:33:00:01:00:02"))
1406 .setPayload(ipv6);
1407 }
1408 this.inPacket = new DefaultInboundPacket(clientCp, eth,
1409 ByteBuffer.wrap(eth.serialize()));
1410 }
1411
1412 @Override
1413 public InboundPacket inPacket() {
1414 return this.inPacket;
1415 }
1416 }
1417
1418 /**
1419 * Generates DHCP6 REPLY packet.
1420 */
1421
1422 private class TestDhcp6ReplyPacketContext extends PacketContextAdapter {
1423 private InboundPacket inPacket;
1424
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001425 public TestDhcp6ReplyPacketContext(byte msgType, ConnectPoint clientCp, MacAddress clientMac,
Kalhee Kim45fede42017-09-05 19:05:06 +00001426 VlanId clientVlan, Ip6Address clientGwAddr,
Kalhee Kim121ba922017-11-01 17:56:44 +00001427 int relayLevel, boolean overWriteFlag, VlanId overWriteVlan) {
Kalhee Kim45fede42017-09-05 19:05:06 +00001428 super(0, null, null, false);
1429
1430
1431 DHCP6 dhcp6Payload = new DHCP6();
Kalhee Kim0c0cb0b2017-09-15 17:43:27 +00001432 buildDhcp6Packet(dhcp6Payload, msgType,
Kalhee Kim45fede42017-09-05 19:05:06 +00001433 IP_FOR_CLIENT_V6,
1434 PREFIX_FOR_CLIENT_V6);
Kalhee Kim121ba922017-11-01 17:56:44 +00001435 byte[] interfaceId = null;
1436 if (relayLevel > 0) {
1437 interfaceId = buildInterfaceId(OUTER_RELAY_MAC,
1438 overWriteFlag ? overWriteVlan.toShort() : OUTER_RELAY_VLAN.toShort(),
1439 OUTER_RELAY_CP);
1440 } else {
1441 interfaceId = buildInterfaceId(clientMac, clientVlan.toShort(), clientCp);
1442 }
Kalhee Kim45fede42017-09-05 19:05:06 +00001443 DHCP6 dhcp6 = new DHCP6();
1444 buildRelayMsg(dhcp6, DHCP6.MsgType.RELAY_REPL.value(),
Yi Tsengaa417a62017-09-08 17:22:51 -07001445 INTERFACE_IP_V6.ipAddress().getIp6Address(),
1446 CLIENT_LL_IP_V6,
1447 (byte) 0, interfaceId,
1448 dhcp6Payload);
Kalhee Kim45fede42017-09-05 19:05:06 +00001449
1450 DHCP6 dhcp6Parent = null;
1451 DHCP6 dhcp6Child = dhcp6;
1452 for (int i = 0; i < relayLevel; i++) { // relayLevel 0 : no relay
1453 dhcp6Parent = new DHCP6();
1454
1455 buildRelayMsg(dhcp6Parent, DHCP6.MsgType.RELAY_REPL.value(),
1456 INTERFACE_IP_V6.ipAddress().getIp6Address(),
1457 OUTER_RELAY_IP_V6,
1458 (byte) relayLevel, interfaceId,
1459 dhcp6Child);
1460
1461 dhcp6Child = dhcp6Parent;
1462 }
1463 if (dhcp6Parent != null) {
1464 dhcp6 = dhcp6Parent;
1465 }
1466
1467
1468 UDP udp = new UDP();
1469 udp.setPayload(dhcp6);
1470 udp.setSourcePort(UDP.DHCP_V6_SERVER_PORT);
1471 udp.setDestinationPort(UDP.DHCP_V6_CLIENT_PORT);
1472 IPv6 ipv6 = new IPv6();
1473 ipv6.setPayload(udp);
1474 ipv6.setNextHeader(IPv6.PROTOCOL_UDP);
1475 ipv6.setDestinationAddress(IP_FOR_CLIENT_V6.toOctets());
1476 ipv6.setSourceAddress(SERVER_IP_V6.toOctets());
1477 Ethernet eth = new Ethernet();
1478 if (relayLevel > 0) {
1479 eth.setEtherType(Ethernet.TYPE_IPV6)
1480 .setVlanID(SERVER_VLAN.toShort())
1481 .setSourceMACAddress(SERVER_MAC)
1482 .setDestinationMACAddress(OUTER_RELAY_MAC)
1483 .setPayload(ipv6);
1484 } else {
1485 eth.setEtherType(Ethernet.TYPE_IPV6)
1486 .setVlanID(SERVER_VLAN.toShort())
1487 .setSourceMACAddress(SERVER_MAC)
1488 .setDestinationMACAddress(CLIENT_MAC)
1489 .setPayload(ipv6);
1490 }
1491
1492 this.inPacket = new DefaultInboundPacket(SERVER_CONNECT_POINT, eth,
1493 ByteBuffer.wrap(eth.serialize()));
1494
1495 }
1496
1497 @Override
1498 public InboundPacket inPacket() {
1499 return this.inPacket;
1500 }
1501 }
1502
Yi Tseng7a38f9a2017-06-09 14:36:40 -07001503}