blob: a179e637e03276bf786029818c668063622b283a [file] [log] [blame]
Yi Tseng7a38f9a2017-06-09 14:36:40 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Yi Tseng7a38f9a2017-06-09 14:36:40 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.dhcprelay;
17
Yi Tseng5479fb82017-09-01 17:24:57 -070018import com.fasterxml.jackson.databind.JsonNode;
19import com.fasterxml.jackson.databind.ObjectMapper;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070020import com.google.common.collect.ImmutableList;
21import com.google.common.collect.ImmutableSet;
22import com.google.common.collect.Lists;
23import com.google.common.collect.Maps;
24import com.google.common.collect.Sets;
Yi Tseng5479fb82017-09-01 17:24:57 -070025import com.google.common.io.Resources;
Yi Tseng2cf59912017-08-24 14:47:34 -070026import org.apache.commons.io.Charsets;
Yi Tseng5479fb82017-09-01 17:24:57 -070027import org.easymock.Capture;
28import org.easymock.CaptureType;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070029import org.easymock.EasyMock;
30import org.junit.After;
31import org.junit.Before;
32import org.junit.Test;
33import org.onlab.packet.ARP;
34import org.onlab.packet.DHCP;
Yi Tseng4fa05832017-08-17 13:08:31 -070035import org.onlab.packet.DeserializationException;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070036import org.onlab.packet.Ethernet;
37import org.onlab.packet.IPv4;
38import org.onlab.packet.Ip4Address;
Kalhee Kim1b5094f2017-09-05 19:05:06 +000039import org.onlab.packet.Ip6Address;
40import org.onlab.packet.IpPrefix;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070041import org.onlab.packet.IpAddress;
42import org.onlab.packet.MacAddress;
43import org.onlab.packet.UDP;
44import org.onlab.packet.VlanId;
45import org.onlab.packet.dhcp.CircuitId;
46import org.onlab.packet.dhcp.DhcpOption;
47import org.onlab.packet.dhcp.DhcpRelayAgentOption;
Kalhee Kim1b5094f2017-09-05 19:05:06 +000048import org.onlab.packet.dhcp.Dhcp6InterfaceIdOption;
49import org.onlab.packet.dhcp.Dhcp6RelayOption;
50import org.onlab.packet.dhcp.Dhcp6IaNaOption;
51import org.onlab.packet.dhcp.Dhcp6IaPdOption;
52import org.onlab.packet.dhcp.Dhcp6IaAddressOption;
53import org.onlab.packet.dhcp.Dhcp6IaPrefixOption;
54import org.onlab.packet.dhcp.Dhcp6Option;
55import org.onosproject.net.ConnectPoint;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070056import org.onosproject.TestApplicationId;
57import org.onosproject.cfg.ComponentConfigService;
58import org.onosproject.core.ApplicationId;
59import org.onosproject.core.CoreService;
Yi Tsenge72fbb52017-08-02 15:03:31 -070060import org.onosproject.dhcprelay.config.DefaultDhcpRelayConfig;
61import org.onosproject.dhcprelay.config.DhcpServerConfig;
Yi Tseng5479fb82017-09-01 17:24:57 -070062import org.onosproject.dhcprelay.config.IgnoreDhcpConfig;
Yi Tsenge72fbb52017-08-02 15:03:31 -070063import org.onosproject.dhcprelay.config.IndirectDhcpRelayConfig;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070064import org.onosproject.dhcprelay.store.DhcpRecord;
65import org.onosproject.dhcprelay.store.DhcpRelayStore;
66import org.onosproject.dhcprelay.store.DhcpRelayStoreEvent;
Yi Tseng76365d82017-09-12 15:55:17 -070067import org.onosproject.net.Device;
Yi Tseng5479fb82017-09-01 17:24:57 -070068import org.onosproject.net.DeviceId;
Yi Tseng76365d82017-09-12 15:55:17 -070069import org.onosproject.net.behaviour.Pipeliner;
70import org.onosproject.net.device.DeviceEvent;
71import org.onosproject.net.device.DeviceService;
Yi Tseng5479fb82017-09-01 17:24:57 -070072import org.onosproject.net.flow.DefaultTrafficSelector;
73import org.onosproject.net.flow.DefaultTrafficTreatment;
74import org.onosproject.net.flow.TrafficSelector;
75import org.onosproject.net.flow.TrafficTreatment;
76import org.onosproject.net.flowobjective.FlowObjectiveService;
77import org.onosproject.net.flowobjective.ForwardingObjective;
78import org.onosproject.net.flowobjective.Objective;
Ray Milkeyfacf2862017-08-03 11:58:29 -070079import org.onosproject.net.intf.Interface;
80import org.onosproject.net.intf.InterfaceServiceAdapter;
Yi Tseng5479fb82017-09-01 17:24:57 -070081import org.onosproject.net.packet.PacketPriority;
Ray Milkey69ec8712017-08-08 13:00:43 -070082import org.onosproject.routeservice.Route;
83import org.onosproject.routeservice.RouteStoreAdapter;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070084import org.onosproject.net.DefaultHost;
85import org.onosproject.net.Host;
86import org.onosproject.net.HostId;
87import org.onosproject.net.HostLocation;
88import org.onosproject.net.config.NetworkConfigRegistry;
89import org.onosproject.net.host.HostDescription;
90import org.onosproject.net.host.HostEvent;
91import org.onosproject.net.host.HostService;
92import org.onosproject.net.host.HostStoreAdapter;
93import 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;
101import org.onosproject.net.provider.ProviderId;
102import org.onosproject.store.StoreDelegate;
103import org.osgi.service.component.ComponentContext;
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000104import org.onlab.packet.DHCP6;
105import org.onlab.packet.IPv6;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700106
Yi Tseng76365d82017-09-12 15:55:17 -0700107import java.io.IOException;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700108import java.nio.ByteBuffer;
109import java.util.Collection;
110import java.util.Dictionary;
111import java.util.List;
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000112import java.util.ArrayList;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700113import java.util.Map;
114import java.util.Optional;
115import java.util.Set;
116import java.util.stream.Collectors;
117
118import static org.easymock.EasyMock.*;
119import static org.junit.Assert.*;
Yi Tseng5479fb82017-09-01 17:24:57 -0700120import static org.onosproject.dhcprelay.DhcpRelayManager.DHCP_RELAY_APP;
Yi Tseng76365d82017-09-12 15:55:17 -0700121import static org.onosproject.dhcprelay.DhcpRelayManager.DHCP_SELECTORS;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700122
123public class DhcpRelayManagerTest {
Yi Tseng5479fb82017-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 Kim1b5094f2017-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 Kim1b5094f2017-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");
141 private static final Interface CLIENT_INTERFACE = new Interface("C1",
142 CLIENT_CP,
143 INTERFACE_IPS,
144 CLIENT_IFACE_MAC,
145 CLIENT_VLAN);
146
147 // DHCP client 2 (will send with option 82, so the vlan should equals to vlan from server)
148 private static final MacAddress CLIENT2_MAC = MacAddress.valueOf("00:00:00:00:00:01");
149 private static final VlanId CLIENT2_VLAN = VlanId.NONE;
150 private static final ConnectPoint CLIENT2_CP = ConnectPoint.deviceConnectPoint("of:0000000000000001/2");
151 private static final MacAddress CLIENT2_IFACE_MAC = MacAddress.valueOf("00:00:00:00:11:01");
152 private static final Interface CLIENT2_INTERFACE = new Interface("C2",
153 CLIENT2_CP,
154 INTERFACE_IPS,
155 CLIENT2_IFACE_MAC,
156 CLIENT2_VLAN);
157
158 // Outer relay information
159 private static final Ip4Address OUTER_RELAY_IP = Ip4Address.valueOf("10.0.5.253");
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000160 private static final Ip6Address OUTER_RELAY_IP_V6 = Ip6Address.valueOf("2001:db8:1::4");
161 private static final Set<IpAddress> OUTER_RELAY_IPS = ImmutableSet.of(OUTER_RELAY_IP, OUTER_RELAY_IP_V6);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700162 private static final MacAddress OUTER_RELAY_MAC = MacAddress.valueOf("00:01:02:03:04:05");
163 private static final VlanId OUTER_RELAY_VLAN = VlanId.NONE;
164 private static final ConnectPoint OUTER_RELAY_CP = ConnectPoint.deviceConnectPoint("of:0000000000000001/2");
165 private static final HostLocation OUTER_REPLAY_HL = new HostLocation(OUTER_RELAY_CP, 0);
166 private static final HostId OUTER_RELAY_HOST_ID = HostId.hostId(OUTER_RELAY_MAC, OUTER_RELAY_VLAN);
167 private static final Host OUTER_RELAY_HOST = new DefaultHost(DhcpRelayManager.PROVIDER_ID,
168 OUTER_RELAY_HOST_ID,
169 OUTER_RELAY_MAC,
170 OUTER_RELAY_VLAN,
171 OUTER_REPLAY_HL,
172 OUTER_RELAY_IPS);
173
174 // DHCP Server
175 private static final MacAddress SERVER_MAC = MacAddress.valueOf("00:00:00:00:00:01");
176 private static final VlanId SERVER_VLAN = VlanId.NONE;
177 private static final ConnectPoint SERVER_CONNECT_POINT =
178 ConnectPoint.deviceConnectPoint("of:0000000000000001/5");
179 private static final HostLocation SERVER_LOCATION =
180 new HostLocation(SERVER_CONNECT_POINT, 0);
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000181 private static final Ip4Address GATEWAY_IP = Ip4Address.valueOf("10.0.5.253");
182 private static final Ip6Address GATEWAY_IP_V6 = Ip6Address.valueOf("2000::105:253");
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700183 private static final Ip4Address SERVER_IP = Ip4Address.valueOf("10.0.3.253");
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000184 private static final Ip6Address SERVER_IP_V6 = Ip6Address.valueOf("2000::103:253");
185 private static final Ip6Address SERVER_IP_V6_MCAST = Ip6Address.valueOf("ff02::1:2");
186 private static final Set<IpAddress> DHCP_SERVER_IPS = ImmutableSet.of(SERVER_IP, SERVER_IP_V6);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700187 private static final HostId SERVER_HOST_ID = HostId.hostId(SERVER_MAC, SERVER_VLAN);
188 private static final Host SERVER_HOST = new DefaultHost(DhcpRelayManager.PROVIDER_ID,
189 SERVER_HOST_ID,
190 SERVER_MAC,
191 SERVER_VLAN,
192 SERVER_LOCATION,
193 DHCP_SERVER_IPS);
194 private static final MacAddress SERVER_IFACE_MAC = MacAddress.valueOf("00:00:00:00:00:01");
195 private static final Interface SERVER_INTERFACE = new Interface("SERVER",
196 SERVER_CONNECT_POINT,
197 INTERFACE_IPS,
198 SERVER_IFACE_MAC,
199 SERVER_VLAN);
200
Yi Tseng4fa05832017-08-17 13:08:31 -0700201 // Relay agent config
202 private static final Ip4Address RELAY_AGENT_IP = Ip4Address.valueOf("10.0.4.254");
203
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700204 // Components
205 private static final ApplicationId APP_ID = TestApplicationId.create(DhcpRelayManager.DHCP_RELAY_APP);
Yi Tsenge72fbb52017-08-02 15:03:31 -0700206 private static final DefaultDhcpRelayConfig CONFIG = new MockDefaultDhcpRelayConfig();
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000207 private static final IndirectDhcpRelayConfig CONFIG_INDIRECT = new MockIndirectDhcpRelayConfig();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700208 private static final Set<Interface> INTERFACES = ImmutableSet.of(
209 CLIENT_INTERFACE,
210 CLIENT2_INTERFACE,
211 SERVER_INTERFACE
212 );
Yi Tseng2cf59912017-08-24 14:47:34 -0700213 private static final String NON_ONOS_CID = "Non-ONOS circuit ID";
Yi Tseng5479fb82017-09-01 17:24:57 -0700214 private static final VlanId IGNORED_VLAN = VlanId.vlanId("100");
215 private static final int IGNORE_CONTROL_PRIORITY = PacketPriority.CONTROL.priorityValue() + 1000;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700216
217 private DhcpRelayManager manager;
218 private MockPacketService packetService;
219 private MockHostStore mockHostStore;
220 private MockRouteStore mockRouteStore;
221 private MockDhcpRelayStore mockDhcpRelayStore;
222
223 @Before
224 public void setup() {
225 manager = new DhcpRelayManager();
226 manager.cfgService = createNiceMock(NetworkConfigRegistry.class);
227
Yi Tsenge72fbb52017-08-02 15:03:31 -0700228 expect(manager.cfgService.getConfig(APP_ID, DefaultDhcpRelayConfig.class))
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700229 .andReturn(CONFIG)
230 .anyTimes();
231
Yi Tsenge72fbb52017-08-02 15:03:31 -0700232 // TODO: add indirect test
233 expect(manager.cfgService.getConfig(APP_ID, IndirectDhcpRelayConfig.class))
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000234 .andReturn(CONFIG_INDIRECT)
Yi Tsenge72fbb52017-08-02 15:03:31 -0700235 .anyTimes();
236
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700237 manager.coreService = createNiceMock(CoreService.class);
238 expect(manager.coreService.registerApplication(anyString()))
239 .andReturn(APP_ID).anyTimes();
240
241 manager.hostService = createNiceMock(HostService.class);
Yi Tseng4fa05832017-08-17 13:08:31 -0700242 expect(manager.hostService.getHostsByIp(anyObject())).andReturn(ImmutableSet.of(SERVER_HOST)).anyTimes();
243 expect(manager.hostService.getHost(OUTER_RELAY_HOST_ID)).andReturn(OUTER_RELAY_HOST).anyTimes();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700244
245 packetService = new MockPacketService();
246 manager.packetService = packetService;
247 manager.compCfgService = createNiceMock(ComponentConfigService.class);
Yi Tseng76365d82017-09-12 15:55:17 -0700248 manager.deviceService = createNiceMock(DeviceService.class);
249
250 Device device = createNiceMock(Device.class);
251 expect(device.is(Pipeliner.class)).andReturn(true).anyTimes();
252
253 expect(manager.deviceService.getDevice(DEV_1_ID)).andReturn(device).anyTimes();
254 expect(manager.deviceService.getDevice(DEV_2_ID)).andReturn(device).anyTimes();
255 replay(manager.deviceService, device);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700256
257 mockHostStore = new MockHostStore();
258 mockRouteStore = new MockRouteStore();
259 mockDhcpRelayStore = new MockDhcpRelayStore();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700260 manager.dhcpRelayStore = mockDhcpRelayStore;
261
262 manager.interfaceService = new MockInterfaceService();
Yi Tseng5479fb82017-09-01 17:24:57 -0700263 manager.flowObjectiveService = EasyMock.niceMock(FlowObjectiveService.class);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700264
Yi Tseng76365d82017-09-12 15:55:17 -0700265
266
Yi Tseng51301292017-07-28 13:02:59 -0700267 Dhcp4HandlerImpl v4Handler = new Dhcp4HandlerImpl();
268 v4Handler.dhcpRelayStore = mockDhcpRelayStore;
269 v4Handler.hostService = manager.hostService;
270 v4Handler.hostStore = mockHostStore;
271 v4Handler.interfaceService = manager.interfaceService;
272 v4Handler.packetService = manager.packetService;
273 v4Handler.routeStore = mockRouteStore;
274 manager.v4Handler = v4Handler;
275
276 // TODO: initialize v6 handler.
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000277 //DhcpHandler v6Handler = createNiceMock(DhcpHandler.class);
278 Dhcp6HandlerImpl v6Handler = new Dhcp6HandlerImpl();
279 v6Handler.dhcpRelayStore = mockDhcpRelayStore;
280 v6Handler.hostService = manager.hostService;
281 v6Handler.hostStore = mockHostStore;
282 v6Handler.interfaceService = manager.interfaceService;
283 v6Handler.packetService = manager.packetService;
284 v6Handler.routeStore = mockRouteStore;
Yi Tsenge72fbb52017-08-02 15:03:31 -0700285 manager.v6Handler = v6Handler;
286
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700287 // properties
288 Dictionary<String, Object> dictionary = createNiceMock(Dictionary.class);
289 expect(dictionary.get("arpEnabled")).andReturn(true).anyTimes();
290 ComponentContext context = createNiceMock(ComponentContext.class);
291 expect(context.getProperties()).andReturn(dictionary).anyTimes();
292
293 EasyMock.replay(manager.cfgService, manager.coreService, manager.hostService,
294 manager.compCfgService, dictionary, context);
295 manager.activate(context);
296 }
297
298 @After
299 public void tearDown() {
300 manager.deactivate();
301 }
302
303 /**
304 * Relay a DHCP packet without option 82.
305 * Should add new host to host store after dhcp ack.
306 */
307 @Test
308 public void relayDhcpWithoutAgentInfo() {
309 // send request
310 packetService.processPacket(new TestDhcpRequestPacketContext(CLIENT_MAC,
311 CLIENT_VLAN,
312 CLIENT_CP,
313 INTERFACE_IP.ipAddress().getIp4Address(),
314 false));
315
316 Set<Host> hosts = ImmutableSet.copyOf(mockHostStore.getHosts());
317 assertEquals(0, hosts.size());
318 assertEquals(0, mockRouteStore.routes.size());
319
320 // send ack
321 packetService.processPacket(new TestDhcpAckPacketContext(CLIENT_CP, CLIENT_MAC,
322 CLIENT_VLAN, INTERFACE_IP.ipAddress().getIp4Address(),
323 false));
324 hosts = ImmutableSet.copyOf(mockHostStore.getHosts());
325 assertEquals(1, hosts.size());
326 assertEquals(0, mockRouteStore.routes.size());
327
328 Host host = hosts.iterator().next();
329 assertEquals(CLIENT_MAC, host.mac());
330 assertEquals(CLIENT_VLAN, host.vlan());
331 assertEquals(CLIENT_CP.deviceId(), host.location().elementId());
332 assertEquals(CLIENT_CP.port(), host.location().port());
333 assertEquals(1, host.ipAddresses().size());
334 assertEquals(IP_FOR_CLIENT, host.ipAddresses().iterator().next());
335 assertEquals(HostId.hostId(CLIENT_MAC, CLIENT_VLAN), host.id());
336 }
337
338 /**
339 * Relay a DHCP packet with option 82 (Indirectly connected host).
340 */
341 @Test
342 public void relayDhcpWithAgentInfo() {
343 // Assume outer dhcp relay agent exists in store already
344 // send request
345 packetService.processPacket(new TestDhcpRequestPacketContext(CLIENT2_MAC,
346 CLIENT2_VLAN,
347 CLIENT2_CP,
348 INTERFACE_IP.ipAddress().getIp4Address(),
349 true));
350
351 Set<Host> hosts = ImmutableSet.copyOf(mockHostStore.getHosts());
352 assertEquals(0, hosts.size());
353 assertEquals(0, mockRouteStore.routes.size());
354
355 // send ack
356 packetService.processPacket(new TestDhcpAckPacketContext(CLIENT2_CP,
357 CLIENT2_MAC,
358 CLIENT2_VLAN,
359 INTERFACE_IP.ipAddress().getIp4Address(),
360 true));
361
362 hosts = ImmutableSet.copyOf(mockHostStore.getHosts());
363 assertEquals(0, hosts.size());
364 assertEquals(1, mockRouteStore.routes.size());
365
366 Route route = mockRouteStore.routes.get(0);
367 assertEquals(OUTER_RELAY_IP, route.nextHop());
368 assertEquals(IP_FOR_CLIENT.toIpPrefix(), route.prefix());
369 assertEquals(Route.Source.STATIC, route.source());
370 }
371
372 @Test
Yi Tseng4fa05832017-08-17 13:08:31 -0700373 public void testWithRelayAgentConfig() throws DeserializationException {
374 manager.v4Handler
375 .setDefaultDhcpServerConfigs(ImmutableList.of(new MockDhcpServerConfig(RELAY_AGENT_IP)));
Yi Tseng4ec727d2017-08-31 11:21:00 -0700376 manager.v4Handler
377 .setIndirectDhcpServerConfigs(ImmutableList.of(new MockDhcpServerConfig(RELAY_AGENT_IP)));
Yi Tseng4fa05832017-08-17 13:08:31 -0700378 packetService.processPacket(new TestDhcpRequestPacketContext(CLIENT2_MAC,
379 CLIENT2_VLAN,
380 CLIENT2_CP,
381 INTERFACE_IP.ipAddress().getIp4Address(),
382 true));
383 OutboundPacket outPacket = packetService.emittedPacket;
384 byte[] outData = outPacket.data().array();
385 Ethernet eth = Ethernet.deserializer().deserialize(outData, 0, outData.length);
386 IPv4 ip = (IPv4) eth.getPayload();
387 UDP udp = (UDP) ip.getPayload();
388 DHCP dhcp = (DHCP) udp.getPayload();
389 assertEquals(RELAY_AGENT_IP.toInt(), dhcp.getGatewayIPAddress());
390 }
391
392 @Test
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700393 public void testArpRequest() throws Exception {
394 packetService.processPacket(new TestArpRequestPacketContext(CLIENT_INTERFACE));
Ray Milkeybd52a052017-08-23 15:23:50 -0700395 OutboundPacket outboundPacket = packetService.emittedPacket;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700396 byte[] outPacketData = outboundPacket.data().array();
397 Ethernet eth = Ethernet.deserializer().deserialize(outPacketData, 0, outPacketData.length);
398
399 assertEquals(eth.getEtherType(), Ethernet.TYPE_ARP);
400 ARP arp = (ARP) eth.getPayload();
401 assertArrayEquals(arp.getSenderHardwareAddress(), CLIENT_INTERFACE.mac().toBytes());
402 }
403
Yi Tseng5479fb82017-09-01 17:24:57 -0700404 /**
405 * Ignores specific vlans from specific devices if config.
406 *
407 * @throws Exception the exception from this test
408 */
409 @Test
410 public void testIgnoreVlan() throws Exception {
411 ObjectMapper om = new ObjectMapper();
412 JsonNode json = om.readTree(Resources.getResource(CONFIG_FILE_PATH));
413 IgnoreDhcpConfig config = new IgnoreDhcpConfig();
414 json = json.path("apps").path(DHCP_RELAY_APP).path(IgnoreDhcpConfig.KEY);
415 config.init(APP_ID, IgnoreDhcpConfig.KEY, json, om, null);
416
417 Capture<Objective> capturedFromDev1 = newCapture(CaptureType.ALL);
418 manager.flowObjectiveService.apply(eq(DEV_1_ID), capture(capturedFromDev1));
Yi Tseng76365d82017-09-12 15:55:17 -0700419 expectLastCall().times(DHCP_SELECTORS.size());
Yi Tseng5479fb82017-09-01 17:24:57 -0700420 Capture<Objective> capturedFromDev2 = newCapture(CaptureType.ALL);
421 manager.flowObjectiveService.apply(eq(DEV_2_ID), capture(capturedFromDev2));
Yi Tseng76365d82017-09-12 15:55:17 -0700422 expectLastCall().times(DHCP_SELECTORS.size());
Yi Tseng5479fb82017-09-01 17:24:57 -0700423 replay(manager.flowObjectiveService);
424 manager.updateConfig(config);
425 verify(manager.flowObjectiveService);
426
427 List<Objective> objectivesFromDev1 = capturedFromDev1.getValues();
428 List<Objective> objectivesFromDev2 = capturedFromDev2.getValues();
429
430 assertTrue(objectivesFromDev1.containsAll(objectivesFromDev2));
431 assertTrue(objectivesFromDev2.containsAll(objectivesFromDev1));
432 TrafficTreatment dropTreatment = DefaultTrafficTreatment.emptyTreatment();
433 dropTreatment.clearedDeferred();
434
435 for (int index = 0; index < objectivesFromDev1.size(); index++) {
436 TrafficSelector selector =
437 DefaultTrafficSelector.builder(DhcpRelayManager.DHCP_SELECTORS.get(index))
438 .matchVlanId(IGNORED_VLAN)
439 .build();
440 ForwardingObjective fwd = (ForwardingObjective) objectivesFromDev1.get(index);
441 assertEquals(selector, fwd.selector());
442 assertEquals(dropTreatment, fwd.treatment());
443 assertEquals(IGNORE_CONTROL_PRIORITY, fwd.priority());
444 assertEquals(ForwardingObjective.Flag.VERSATILE, fwd.flag());
445 assertEquals(Objective.Operation.ADD, fwd.op());
Yi Tseng76365d82017-09-12 15:55:17 -0700446 fwd.context().ifPresent(ctx -> {
447 ctx.onSuccess(fwd);
448 });
Yi Tseng5479fb82017-09-01 17:24:57 -0700449 }
Yi Tseng76365d82017-09-12 15:55:17 -0700450 objectivesFromDev2.forEach(obj -> obj.context().ifPresent(ctx -> ctx.onSuccess(obj)));
Yi Tseng5479fb82017-09-01 17:24:57 -0700451 assertEquals(2, manager.ignoredVlans.size());
452 }
453
454 /**
455 * "IgnoreVlan" policy should be removed when the config removed.
456 */
457 @Test
458 public void testRemoveIgnoreVlan() {
459 manager.ignoredVlans.put(DEV_1_ID, IGNORED_VLAN);
460 manager.ignoredVlans.put(DEV_2_ID, IGNORED_VLAN);
461 IgnoreDhcpConfig config = new IgnoreDhcpConfig();
462
463 Capture<Objective> capturedFromDev1 = newCapture(CaptureType.ALL);
464 manager.flowObjectiveService.apply(eq(DEV_1_ID), capture(capturedFromDev1));
Yi Tseng76365d82017-09-12 15:55:17 -0700465 expectLastCall().times(DHCP_SELECTORS.size());
Yi Tseng5479fb82017-09-01 17:24:57 -0700466 Capture<Objective> capturedFromDev2 = newCapture(CaptureType.ALL);
467 manager.flowObjectiveService.apply(eq(DEV_2_ID), capture(capturedFromDev2));
Yi Tseng76365d82017-09-12 15:55:17 -0700468 expectLastCall().times(DHCP_SELECTORS.size());
Yi Tseng5479fb82017-09-01 17:24:57 -0700469 replay(manager.flowObjectiveService);
470 manager.removeConfig(config);
471 verify(manager.flowObjectiveService);
472
473 List<Objective> objectivesFromDev1 = capturedFromDev1.getValues();
474 List<Objective> objectivesFromDev2 = capturedFromDev2.getValues();
475
476 assertTrue(objectivesFromDev1.containsAll(objectivesFromDev2));
477 assertTrue(objectivesFromDev2.containsAll(objectivesFromDev1));
478 TrafficTreatment dropTreatment = DefaultTrafficTreatment.emptyTreatment();
479 dropTreatment.clearedDeferred();
480
481 for (int index = 0; index < objectivesFromDev1.size(); index++) {
482 TrafficSelector selector =
483 DefaultTrafficSelector.builder(DhcpRelayManager.DHCP_SELECTORS.get(index))
484 .matchVlanId(IGNORED_VLAN)
485 .build();
486 ForwardingObjective fwd = (ForwardingObjective) objectivesFromDev1.get(index);
487 assertEquals(selector, fwd.selector());
488 assertEquals(dropTreatment, fwd.treatment());
489 assertEquals(IGNORE_CONTROL_PRIORITY, fwd.priority());
490 assertEquals(ForwardingObjective.Flag.VERSATILE, fwd.flag());
491 assertEquals(Objective.Operation.REMOVE, fwd.op());
Yi Tseng76365d82017-09-12 15:55:17 -0700492 fwd.context().ifPresent(ctx -> {
493 ctx.onSuccess(fwd);
494 });
Yi Tseng5479fb82017-09-01 17:24:57 -0700495 }
Yi Tseng76365d82017-09-12 15:55:17 -0700496 objectivesFromDev2.forEach(obj -> obj.context().ifPresent(ctx -> ctx.onSuccess(obj)));
Yi Tseng5479fb82017-09-01 17:24:57 -0700497 assertEquals(0, manager.ignoredVlans.size());
498 }
499
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000500 /**
Yi Tseng76365d82017-09-12 15:55:17 -0700501 * Should ignore ignore rules installation when device not available.
502 */
503 @Test
504 public void testIgnoreUnknownDevice() throws IOException {
505 reset(manager.deviceService);
506 Device device = createNiceMock(Device.class);
507 expect(device.is(Pipeliner.class)).andReturn(true).anyTimes();
508
509 expect(manager.deviceService.getDevice(DEV_1_ID)).andReturn(device).anyTimes();
510 expect(manager.deviceService.getDevice(DEV_2_ID)).andReturn(null).anyTimes();
511
512 ObjectMapper om = new ObjectMapper();
513 JsonNode json = om.readTree(Resources.getResource(CONFIG_FILE_PATH));
514 IgnoreDhcpConfig config = new IgnoreDhcpConfig();
515 json = json.path("apps").path(DHCP_RELAY_APP).path(IgnoreDhcpConfig.KEY);
516 config.init(APP_ID, IgnoreDhcpConfig.KEY, json, om, null);
517
518 Capture<Objective> capturedFromDev1 = newCapture(CaptureType.ALL);
519 manager.flowObjectiveService.apply(eq(DEV_1_ID), capture(capturedFromDev1));
520 expectLastCall().times(DHCP_SELECTORS.size());
521 replay(manager.flowObjectiveService, manager.deviceService, device);
522
523 manager.updateConfig(config);
524 capturedFromDev1.getValues().forEach(obj -> obj.context().ifPresent(ctx -> ctx.onSuccess(obj)));
525
526 assertEquals(1, manager.ignoredVlans.size());
527 }
528
529 /**
530 * Should try install ignore rules when device comes up.
531 */
532 @Test
533 public void testInstallIgnoreRuleWhenDeviceComesUp() throws IOException {
534 ObjectMapper om = new ObjectMapper();
535 JsonNode json = om.readTree(Resources.getResource(CONFIG_FILE_PATH));
536 IgnoreDhcpConfig config = new IgnoreDhcpConfig();
537 json = json.path("apps").path(DHCP_RELAY_APP).path(IgnoreDhcpConfig.KEY);
538 config.init(APP_ID, IgnoreDhcpConfig.KEY, json, om, null);
539
540 reset(manager.cfgService, manager.flowObjectiveService, manager.deviceService);
541 expect(manager.cfgService.getConfig(APP_ID, IgnoreDhcpConfig.class))
542 .andReturn(config).anyTimes();
543
544 Device device = createNiceMock(Device.class);
545 expect(device.is(Pipeliner.class)).andReturn(true).anyTimes();
546 expect(device.id()).andReturn(DEV_1_ID).anyTimes();
547 expect(manager.deviceService.getDevice(DEV_1_ID)).andReturn(device).anyTimes();
548 DeviceEvent event = new DeviceEvent(DeviceEvent.Type.DEVICE_ADDED, device);
549 Capture<Objective> capturedFromDev1 = newCapture(CaptureType.ALL);
550 manager.flowObjectiveService.apply(eq(DEV_1_ID), capture(capturedFromDev1));
551 expectLastCall().times(DHCP_SELECTORS.size());
552 replay(manager.cfgService, manager.flowObjectiveService, manager.deviceService, device);
553 assertEquals(0, manager.ignoredVlans.size());
554 manager.deviceListener.event(event);
555 capturedFromDev1.getValues().forEach(obj -> obj.context().ifPresent(ctx -> ctx.onSuccess(obj)));
556 assertEquals(1, manager.ignoredVlans.size());
557 }
558
559 /**
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000560 * Relay a DHCP6 packet without relay option
561 * Note: Should add new host to host store after dhcp ack.
562 */
563 @Test
564 public void relayDhcp6WithoutAgentInfo() {
565 // send request
566 packetService.processPacket(new TestDhcp6RequestPacketContext(CLIENT_MAC,
567 VlanId.NONE,
568 CLIENT_CP,
569 INTERFACE_IP_V6.ipAddress().getIp6Address(),
570 0));
571
572 Set<Host> hosts = ImmutableSet.copyOf(mockHostStore.getHosts());
573 assertEquals(0, hosts.size());
574 assertEquals(0, mockRouteStore.routes.size());
575
576 // send reply
577 packetService.processPacket(new TestDhcp6ReplyPacketContext(CLIENT_CP, CLIENT_MAC,
578 CLIENT_VLAN,
579 INTERFACE_IP_V6.ipAddress().getIp6Address(),
580 0));
581 hosts = ImmutableSet.copyOf(mockHostStore.getHosts());
582 assertEquals(1, hosts.size());
583 assertEquals(0, mockRouteStore.routes.size());
584
585 Host host = hosts.iterator().next();
586 assertEquals(CLIENT_MAC, host.mac());
587 assertEquals(CLIENT_VLAN, host.vlan());
588 assertEquals(CLIENT_CP.deviceId(), host.location().elementId());
589 assertEquals(CLIENT_CP.port(), host.location().port());
590 assertEquals(1, host.ipAddresses().size());
591 assertEquals(IP_FOR_CLIENT_V6, host.ipAddresses().iterator().next());
592 assertEquals(HostId.hostId(CLIENT_MAC, CLIENT_VLAN), host.id());
593 }
594
595 /**
596 * Relay a DHCP6 packet with Relay Message opion (Indirectly connected host).
597 */
598 @Test
599 public void relayDhcp6WithAgentInfo() {
600 // Assume outer dhcp6 relay agent exists in store already
601 // send request
602 packetService.processPacket(new TestDhcp6RequestPacketContext(CLIENT2_MAC,
603 CLIENT2_VLAN,
604 CLIENT2_CP,
605 INTERFACE_IP_V6.ipAddress().getIp6Address(),
606 1));
607
608 Set<Host> hosts = ImmutableSet.copyOf(mockHostStore.getHosts());
609 assertEquals(0, hosts.size());
610 assertEquals(0, mockRouteStore.routes.size());
611
612 // send reply
613 packetService.processPacket(new TestDhcp6ReplyPacketContext(CLIENT2_CP,
614 CLIENT2_MAC,
615 CLIENT2_VLAN,
616 INTERFACE_IP_V6.ipAddress().getIp6Address(),
617 1));
618
619 hosts = ImmutableSet.copyOf(mockHostStore.getHosts());
620 assertEquals(0, hosts.size());
621 assertEquals(2, mockRouteStore.routes.size()); // ipAddress and prefix
622
623 Route route = mockRouteStore.routes.get(0);
624 assertEquals(OUTER_RELAY_IP_V6, route.nextHop());
625 assertEquals(IP_FOR_CLIENT_V6.toIpPrefix(), route.prefix());
626 assertEquals(Route.Source.STATIC, route.source());
627 }
Yi Tsenge72fbb52017-08-02 15:03:31 -0700628 private static class MockDefaultDhcpRelayConfig extends DefaultDhcpRelayConfig {
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700629 @Override
630 public boolean isValid() {
631 return true;
632 }
633
634 @Override
Yi Tsenge72fbb52017-08-02 15:03:31 -0700635 public List<DhcpServerConfig> dhcpServerConfigs() {
Yi Tseng4fa05832017-08-17 13:08:31 -0700636 return ImmutableList.of(new MockDhcpServerConfig(null));
Yi Tsenge72fbb52017-08-02 15:03:31 -0700637 }
638 }
639
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000640 private static class MockIndirectDhcpRelayConfig extends IndirectDhcpRelayConfig {
641 @Override
642 public boolean isValid() {
643 return true;
644 }
645
646 @Override
647 public List<DhcpServerConfig> dhcpServerConfigs() {
648 return ImmutableList.of(new MockDhcpServerConfig(null));
649 }
650 }
651
Yi Tsenge72fbb52017-08-02 15:03:31 -0700652 private static class MockDhcpServerConfig extends DhcpServerConfig {
Yi Tseng4fa05832017-08-17 13:08:31 -0700653 Ip4Address relayAgentIp;
654
655 /**
656 * Create mocked version DHCP server config.
657 *
658 * @param relayAgentIp the relay agent Ip config; null if we don't need it
659 */
660 public MockDhcpServerConfig(Ip4Address relayAgentIp) {
661 this.relayAgentIp = relayAgentIp;
662 }
663
664 @Override
665 public Optional<Ip4Address> getRelayAgentIp4() {
666 return Optional.ofNullable(relayAgentIp);
667 }
668
Yi Tsenge72fbb52017-08-02 15:03:31 -0700669 @Override
670 public Optional<ConnectPoint> getDhcpServerConnectPoint() {
671 return Optional.of(SERVER_CONNECT_POINT);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700672 }
673
Yi Tsenge72fbb52017-08-02 15:03:31 -0700674 @Override
675 public Optional<Ip4Address> getDhcpServerIp4() {
676 return Optional.of(SERVER_IP);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700677 }
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000678
679 @Override
680 public Optional<Ip4Address> getDhcpGatewayIp4() {
681 return Optional.of(GATEWAY_IP);
682 }
683
684 @Override
685 public Optional<Ip6Address> getDhcpServerIp6() {
686 return Optional.of(SERVER_IP_V6);
687 }
688
689 @Override
690 public Optional<Ip6Address> getDhcpGatewayIp6() {
691 return Optional.of(GATEWAY_IP_V6);
692 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700693 }
694
695 private class MockHostStore extends HostStoreAdapter {
696
697 private final Map<HostId, HostDescription> hosts = Maps.newHashMap();
698
699 @Override
700 public HostEvent createOrUpdateHost(ProviderId providerId, HostId hostId,
701 HostDescription hostDescription,
702 boolean replaceIps) {
703 hosts.put(hostId, hostDescription);
704
705 // not necessary to return host event in this test.
706 return null;
707 }
708
709 public HostDescription hostDesc(HostId hostId) {
710 return hosts.get(hostId);
711 }
712
713 @Override
714 public Iterable<Host> getHosts() {
715 return hosts.values().stream()
716 .map(hd -> new DefaultHost(DhcpRelayManager.PROVIDER_ID,
717 HostId.hostId(hd.hwAddress(), hd.vlan()),
718 hd.hwAddress(),
719 hd.vlan(), hd.locations(),
720 hd.ipAddress(), false))
721 .collect(Collectors.toList());
722 }
723 }
724
725 private class MockRouteStore extends RouteStoreAdapter {
726 private List<Route> routes = Lists.newArrayList();
727
728 @Override
729 public void updateRoute(Route route) {
730 routes.add(route);
731 }
732 }
733
734 private class MockInterfaceService extends InterfaceServiceAdapter {
735
736 @Override
737 public Set<Interface> getInterfaces() {
738 return INTERFACES;
739 }
740
741 @Override
742 public Set<Interface> getInterfacesByIp(IpAddress ip) {
743 return INTERFACES.stream()
744 .filter(iface -> {
745 return iface.ipAddressesList().stream()
746 .anyMatch(ifaceIp -> ifaceIp.ipAddress().equals(ip));
747 })
748 .collect(Collectors.toSet());
749 }
750
751 @Override
752 public Set<Interface> getInterfacesByPort(ConnectPoint port) {
753 return INTERFACES.stream()
754 .filter(iface -> iface.connectPoint().equals(port))
755 .collect(Collectors.toSet());
756 }
757 }
758
759 private class MockDhcpRelayStore implements DhcpRelayStore {
760 StoreDelegate<DhcpRelayStoreEvent> delegate;
761 private Map<HostId, DhcpRecord> records = Maps.newHashMap();
762
763 @Override
764 public void updateDhcpRecord(HostId hostId, DhcpRecord dhcpRecord) {
765 records.put(hostId, dhcpRecord);
766 DhcpRelayStoreEvent event = new DhcpRelayStoreEvent(DhcpRelayStoreEvent.Type.UPDATED,
767 dhcpRecord);
768 if (delegate != null) {
769 delegate.notify(event);
770 }
771 }
772
773 @Override
774 public Optional<DhcpRecord> getDhcpRecord(HostId hostId) {
775 return Optional.ofNullable(records.get(hostId));
776 }
777
778 @Override
779 public Collection<DhcpRecord> getDhcpRecords() {
780 return records.values();
781 }
782
783 @Override
784 public Optional<DhcpRecord> removeDhcpRecord(HostId hostId) {
785 DhcpRecord dhcpRecord = records.remove(hostId);
786 if (dhcpRecord != null) {
787 DhcpRelayStoreEvent event = new DhcpRelayStoreEvent(DhcpRelayStoreEvent.Type.REMOVED,
788 dhcpRecord);
789 if (delegate != null) {
790 delegate.notify(event);
791 }
792 }
793 return Optional.ofNullable(dhcpRecord);
794 }
795
796 @Override
797 public void setDelegate(StoreDelegate<DhcpRelayStoreEvent> delegate) {
798 this.delegate = delegate;
799 }
800
801 @Override
802 public void unsetDelegate(StoreDelegate<DhcpRelayStoreEvent> delegate) {
803 this.delegate = null;
804 }
805
806 @Override
807 public boolean hasDelegate() {
808 return this.delegate != null;
809 }
810 }
811
812 private class MockPacketService extends PacketServiceAdapter {
813 Set<PacketProcessor> packetProcessors = Sets.newHashSet();
Ray Milkeybd52a052017-08-23 15:23:50 -0700814 OutboundPacket emittedPacket;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700815
816 @Override
817 public void addProcessor(PacketProcessor processor, int priority) {
818 packetProcessors.add(processor);
819 }
820
821 public void processPacket(PacketContext packetContext) {
822 packetProcessors.forEach(p -> p.process(packetContext));
823 }
824
825 @Override
826 public void emit(OutboundPacket packet) {
Ray Milkeybd52a052017-08-23 15:23:50 -0700827 this.emittedPacket = packet;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700828 }
829 }
830
831
832
833 /**
834 * Generates DHCP REQUEST packet.
835 */
836 private class TestDhcpRequestPacketContext extends PacketContextAdapter {
837
838
839 private InboundPacket inPacket;
840
841 public TestDhcpRequestPacketContext(MacAddress clientMac, VlanId vlanId,
842 ConnectPoint clientCp,
843 Ip4Address clientGwAddr,
844 boolean withNonOnosRelayInfo) {
845 super(0, null, null, false);
846 byte[] dhcpMsgType = new byte[1];
847 dhcpMsgType[0] = (byte) DHCP.MsgType.DHCPREQUEST.getValue();
848
849 DhcpOption dhcpOption = new DhcpOption();
850 dhcpOption.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue());
851 dhcpOption.setData(dhcpMsgType);
852 dhcpOption.setLength((byte) 1);
853 DhcpOption endOption = new DhcpOption();
854 endOption.setCode(DHCP.DHCPOptionCode.OptionCode_END.getValue());
855
856 DHCP dhcp = new DHCP();
857 dhcp.setHardwareType(DHCP.HWTYPE_ETHERNET);
858 dhcp.setHardwareAddressLength((byte) 6);
859 dhcp.setClientHardwareAddress(clientMac.toBytes());
860 if (withNonOnosRelayInfo) {
861 DhcpRelayAgentOption relayOption = new DhcpRelayAgentOption();
862 DhcpOption circuitIdOption = new DhcpOption();
863 CircuitId circuitId = new CircuitId("Custom option", VlanId.NONE);
864 byte[] cid = circuitId.serialize();
865 circuitIdOption.setCode(DhcpRelayAgentOption.RelayAgentInfoOptions.CIRCUIT_ID.getValue());
866 circuitIdOption.setLength((byte) cid.length);
867 circuitIdOption.setData(cid);
868 relayOption.setCode(DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue());
869 relayOption.addSubOption(circuitIdOption);
870 dhcp.setOptions(ImmutableList.of(dhcpOption, relayOption, endOption));
871 dhcp.setGatewayIPAddress(OUTER_RELAY_IP.getIp4Address().toInt());
872 } else {
873 dhcp.setOptions(ImmutableList.of(dhcpOption, endOption));
874 }
875
876
877 UDP udp = new UDP();
878 udp.setPayload(dhcp);
879 udp.setSourcePort(UDP.DHCP_CLIENT_PORT);
880 udp.setDestinationPort(UDP.DHCP_SERVER_PORT);
881
882 IPv4 ipv4 = new IPv4();
883 ipv4.setPayload(udp);
884 ipv4.setDestinationAddress(SERVER_IP.toInt());
885 ipv4.setSourceAddress(clientGwAddr.toInt());
886
887 Ethernet eth = new Ethernet();
888 if (withNonOnosRelayInfo) {
889 eth.setEtherType(Ethernet.TYPE_IPV4)
890 .setVlanID(vlanId.toShort())
891 .setSourceMACAddress(OUTER_RELAY_MAC)
892 .setDestinationMACAddress(MacAddress.BROADCAST)
893 .setPayload(ipv4);
894 } else {
895 eth.setEtherType(Ethernet.TYPE_IPV4)
896 .setVlanID(vlanId.toShort())
897 .setSourceMACAddress(clientMac)
898 .setDestinationMACAddress(MacAddress.BROADCAST)
899 .setPayload(ipv4);
900 }
901
902 this.inPacket = new DefaultInboundPacket(clientCp, eth,
903 ByteBuffer.wrap(eth.serialize()));
904 }
905
906 @Override
907 public InboundPacket inPacket() {
908 return this.inPacket;
909 }
910 }
911
912 /**
913 * Generates DHCP ACK packet.
914 */
915 private class TestDhcpAckPacketContext extends PacketContextAdapter {
916 private InboundPacket inPacket;
917
918 public TestDhcpAckPacketContext(ConnectPoint clientCp, MacAddress clientMac,
919 VlanId clientVlan, Ip4Address clientGwAddr,
920 boolean withNonOnosRelayInfo) {
921 super(0, null, null, false);
922
923 byte[] dhcpMsgType = new byte[1];
924 dhcpMsgType[0] = (byte) DHCP.MsgType.DHCPACK.getValue();
925
926 DhcpOption dhcpOption = new DhcpOption();
927 dhcpOption.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue());
928 dhcpOption.setData(dhcpMsgType);
929 dhcpOption.setLength((byte) 1);
930
931 DhcpOption endOption = new DhcpOption();
932 endOption.setCode(DHCP.DHCPOptionCode.OptionCode_END.getValue());
933
934 DHCP dhcp = new DHCP();
935 if (withNonOnosRelayInfo) {
936 DhcpRelayAgentOption relayOption = new DhcpRelayAgentOption();
937 DhcpOption circuitIdOption = new DhcpOption();
Yi Tseng2cf59912017-08-24 14:47:34 -0700938 String circuitId = NON_ONOS_CID;
939 byte[] cid = circuitId.getBytes(Charsets.US_ASCII);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700940 circuitIdOption.setCode(DhcpRelayAgentOption.RelayAgentInfoOptions.CIRCUIT_ID.getValue());
941 circuitIdOption.setLength((byte) cid.length);
942 circuitIdOption.setData(cid);
943 relayOption.setCode(DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue());
944 relayOption.addSubOption(circuitIdOption);
945 dhcp.setOptions(ImmutableList.of(dhcpOption, relayOption, endOption));
946 dhcp.setGatewayIPAddress(OUTER_RELAY_IP.getIp4Address().toInt());
947 } else {
948 CircuitId cid = new CircuitId(clientCp.toString(), clientVlan);
949 byte[] circuitId = cid.serialize();
950 DhcpOption circuitIdSubOption = new DhcpOption();
951 circuitIdSubOption.setCode(DhcpRelayAgentOption.RelayAgentInfoOptions.CIRCUIT_ID.getValue());
952 circuitIdSubOption.setData(circuitId);
953 circuitIdSubOption.setLength((byte) circuitId.length);
954
955 DhcpRelayAgentOption relayInfoOption = new DhcpRelayAgentOption();
956 relayInfoOption.setCode(DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue());
957 relayInfoOption.addSubOption(circuitIdSubOption);
958 dhcp.setOptions(ImmutableList.of(dhcpOption, relayInfoOption, endOption));
959 dhcp.setGatewayIPAddress(clientGwAddr.toInt());
960 }
961 dhcp.setHardwareType(DHCP.HWTYPE_ETHERNET);
962 dhcp.setHardwareAddressLength((byte) 6);
963 dhcp.setClientHardwareAddress(clientMac.toBytes());
964 dhcp.setYourIPAddress(IP_FOR_CLIENT.toInt());
965
966 UDP udp = new UDP();
967 udp.setPayload(dhcp);
968 udp.setSourcePort(UDP.DHCP_SERVER_PORT);
969 udp.setDestinationPort(UDP.DHCP_CLIENT_PORT);
970 IPv4 ipv4 = new IPv4();
971 ipv4.setPayload(udp);
972 ipv4.setDestinationAddress(IP_FOR_CLIENT.toString());
973 ipv4.setSourceAddress(SERVER_IP.toString());
974 Ethernet eth = new Ethernet();
975 if (withNonOnosRelayInfo) {
976 eth.setEtherType(Ethernet.TYPE_IPV4)
977 .setVlanID(SERVER_VLAN.toShort())
978 .setSourceMACAddress(SERVER_MAC)
979 .setDestinationMACAddress(OUTER_RELAY_MAC)
980 .setPayload(ipv4);
981 } else {
982 eth.setEtherType(Ethernet.TYPE_IPV4)
983 .setVlanID(SERVER_VLAN.toShort())
984 .setSourceMACAddress(SERVER_MAC)
985 .setDestinationMACAddress(CLIENT_MAC)
986 .setPayload(ipv4);
987 }
988
989 this.inPacket = new DefaultInboundPacket(SERVER_CONNECT_POINT, eth,
990 ByteBuffer.wrap(eth.serialize()));
991
992 }
993
994 @Override
995 public InboundPacket inPacket() {
996 return this.inPacket;
997 }
998 }
999
1000 private class TestArpRequestPacketContext extends PacketContextAdapter {
1001 private InboundPacket inPacket;
1002
1003 public TestArpRequestPacketContext(Interface fromInterface) {
1004 super(0, null, null, false);
1005 ARP arp = new ARP();
1006 arp.setOpCode(ARP.OP_REQUEST);
1007
1008 IpAddress targetIp = fromInterface.ipAddressesList().get(0).ipAddress();
1009 arp.setTargetProtocolAddress(targetIp.toOctets());
1010 arp.setTargetHardwareAddress(MacAddress.BROADCAST.toBytes());
1011 arp.setSenderHardwareAddress(MacAddress.NONE.toBytes());
1012 arp.setSenderProtocolAddress(Ip4Address.valueOf(0).toOctets());
1013 arp.setHardwareAddressLength((byte) MacAddress.MAC_ADDRESS_LENGTH);
1014 Ethernet eth = new Ethernet();
1015 eth.setEtherType(Ethernet.TYPE_ARP);
1016 eth.setSourceMACAddress(MacAddress.NONE);
1017 eth.setDestinationMACAddress(MacAddress.BROADCAST);
1018 eth.setVlanID(fromInterface.vlan().toShort());
1019 eth.setPayload(arp);
1020
1021 this.inPacket = new DefaultInboundPacket(fromInterface.connectPoint(), eth,
1022 ByteBuffer.wrap(eth.serialize()));
1023 }
1024
1025 @Override
1026 public InboundPacket inPacket() {
1027 return this.inPacket;
1028 }
1029 }
Kalhee Kim1b5094f2017-09-05 19:05:06 +00001030
1031 /**
1032 * Generates DHCP6 REQUEST packet.
1033 */
1034 private void buildDhcp6Packet(DHCP6 dhcp6, byte msgType, Ip6Address ip6Addr, IpPrefix prefix) {
1035
1036 // build address option
1037 Dhcp6IaAddressOption iaAddressOption = new Dhcp6IaAddressOption();
1038 iaAddressOption.setCode(DHCP6.OptionCode.IAADDR.value());
1039 iaAddressOption.setIp6Address(ip6Addr);
1040 iaAddressOption.setPreferredLifetime(3600);
1041 iaAddressOption.setValidLifetime(1200);
1042 iaAddressOption.setLength((short) Dhcp6IaAddressOption.DEFAULT_LEN);
1043
1044 Dhcp6IaNaOption iaNaOption = new Dhcp6IaNaOption();
1045 iaNaOption.setCode(DHCP6.OptionCode.IA_NA.value());
1046 iaNaOption.setIaId(0);
1047 iaNaOption.setT1(302400);
1048 iaNaOption.setT2(483840);
1049 List<Dhcp6Option> iaNaSubOptions = new ArrayList<Dhcp6Option>();
1050 iaNaSubOptions.add(iaAddressOption);
1051 iaNaOption.setOptions(iaNaSubOptions);
1052 iaNaOption.setLength((short) (Dhcp6IaNaOption.DEFAULT_LEN + iaAddressOption.getLength()));
1053
1054 // build prefix option
1055 Dhcp6IaPrefixOption iaPrefixOption = new Dhcp6IaPrefixOption();
1056 iaPrefixOption.setCode(DHCP6.OptionCode.IAPREFIX.value());
1057 iaPrefixOption.setIp6Prefix(prefix.address().getIp6Address());
1058 iaPrefixOption.setPrefixLength((byte) prefix.prefixLength());
1059 iaPrefixOption.setPreferredLifetime(3601);
1060 iaPrefixOption.setValidLifetime(1201);
1061 iaPrefixOption.setLength((short) Dhcp6IaPrefixOption.DEFAULT_LEN);
1062
1063 Dhcp6IaPdOption iaPdOption = new Dhcp6IaPdOption();
1064 iaPdOption.setCode(DHCP6.OptionCode.IA_PD.value());
1065 iaPdOption.setIaId(0);
1066 iaPdOption.setT1(302401);
1067 iaPdOption.setT2(483841);
1068 List<Dhcp6Option> iaPdSubOptions = new ArrayList<Dhcp6Option>();
1069 iaPdSubOptions.add(iaPrefixOption);
1070 iaPdOption.setOptions(iaPdSubOptions);
1071 iaPdOption.setLength((short) (Dhcp6IaPdOption.DEFAULT_LEN + iaPrefixOption.getLength()));
1072
1073 dhcp6.setMsgType(msgType);
1074 List<Dhcp6Option> dhcp6Options = new ArrayList<Dhcp6Option>();
1075 dhcp6Options.add(iaNaOption);
1076 dhcp6Options.add(iaPdOption);
1077 dhcp6.setOptions(dhcp6Options);
1078
1079 }
1080
1081 private void buildRelayMsg(DHCP6 dhcp6Relay, byte msgType, Ip6Address linkAddr,
1082 Ip6Address peerAddr, byte hop, byte[] interfaceIdBytes,
1083 DHCP6 dhcp6Payload) {
1084
1085 dhcp6Relay.setMsgType(msgType);
1086
1087 dhcp6Relay.setLinkAddress(linkAddr.toOctets());
1088 dhcp6Relay.setPeerAddress(peerAddr.toOctets());
1089 dhcp6Relay.setHopCount(hop);
1090 List<Dhcp6Option> options = new ArrayList<Dhcp6Option>();
1091
1092 // interfaceId option
1093 Dhcp6Option interfaceId = new Dhcp6Option();
1094 interfaceId.setCode(DHCP6.OptionCode.INTERFACE_ID.value());
1095
1096
1097 interfaceId.setData(interfaceIdBytes);
1098 interfaceId.setLength((short) interfaceIdBytes.length);
1099 Dhcp6InterfaceIdOption interfaceIdOption = new Dhcp6InterfaceIdOption(interfaceId);
1100 ByteBuffer bb = ByteBuffer.wrap(interfaceIdBytes);
1101
1102 byte[] macAddr = new byte[MacAddress.MAC_ADDRESS_LENGTH];
1103 byte[] port = new byte[21];
1104 bb.get(macAddr);
1105 bb.get(); // separator
1106 bb.get(port);
1107 interfaceIdOption.setMacAddress(MacAddress.valueOf(macAddr));
1108 interfaceIdOption.setInPort(port);
1109
1110 options.add(interfaceIdOption);
1111
1112 // relay message option
1113 Dhcp6Option relayMsgOption = new Dhcp6Option();
1114 relayMsgOption.setCode(DHCP6.OptionCode.RELAY_MSG.value());
1115 byte[] dhcp6PayloadByte = dhcp6Payload.serialize();
1116 relayMsgOption.setLength((short) dhcp6PayloadByte.length);
1117 relayMsgOption.setPayload(dhcp6Payload);
1118 Dhcp6RelayOption relayOpt = new Dhcp6RelayOption(relayMsgOption);
1119
1120 options.add(relayOpt);
1121
1122 dhcp6Relay.setOptions(options);
1123 }
1124 private byte[] buildInterfaceId(MacAddress clientMac, ConnectPoint clientCp) {
1125 String inPortString = "-" + clientCp.toString();
1126 byte[] clientSoureMacBytes = clientMac.toBytes();
1127 byte[] inPortStringBytes = inPortString.getBytes();
1128 byte[] interfaceIdBytes = new byte[clientSoureMacBytes.length + inPortStringBytes.length];
1129
1130 System.arraycopy(clientSoureMacBytes, 0, interfaceIdBytes, 0, clientSoureMacBytes.length);
1131 System.arraycopy(inPortStringBytes, 0, interfaceIdBytes, clientSoureMacBytes.length, inPortStringBytes.length);
1132
1133 return interfaceIdBytes;
1134 }
1135
1136 private class TestDhcp6RequestPacketContext extends PacketContextAdapter {
1137
1138
1139 private InboundPacket inPacket;
1140
1141
1142 public TestDhcp6RequestPacketContext(MacAddress clientMac, VlanId vlanId,
1143 ConnectPoint clientCp,
1144 Ip6Address clientGwAddr,
1145 int relayLevel) {
1146 super(0, null, null, false);
1147
1148 DHCP6 dhcp6 = new DHCP6();
1149 if (relayLevel > 0) {
1150 DHCP6 dhcp6Payload = new DHCP6();
1151 buildDhcp6Packet(dhcp6Payload, DHCP6.MsgType.REQUEST.value(),
1152 IP_FOR_CLIENT_V6,
1153 PREFIX_FOR_ZERO);
1154 DHCP6 dhcp6Parent = null;
1155 DHCP6 dhcp6Child = dhcp6Payload;
1156 for (int i = 0; i < relayLevel; i++) {
1157 dhcp6Parent = new DHCP6();
1158 byte[] interfaceId = buildInterfaceId(clientMac, clientCp);
1159 buildRelayMsg(dhcp6Parent, DHCP6.MsgType.RELAY_FORW.value(),
1160 INTERFACE_IP_V6.ipAddress().getIp6Address(),
1161 OUTER_RELAY_IP_V6,
1162 (byte) (relayLevel - 1), interfaceId,
1163 dhcp6Child);
1164 dhcp6Child = dhcp6Parent;
1165 }
1166 if (dhcp6Parent != null) {
1167 dhcp6 = dhcp6Parent;
1168 }
1169 } else {
1170 buildDhcp6Packet(dhcp6, DHCP6.MsgType.REQUEST.value(),
1171 IP_FOR_CLIENT_V6,
1172 PREFIX_FOR_ZERO);
1173 }
1174
1175 UDP udp = new UDP();
1176 udp.setPayload(dhcp6);
1177 if (relayLevel > 0) {
1178 udp.setSourcePort(UDP.DHCP_V6_SERVER_PORT);
1179 } else {
1180 udp.setSourcePort(UDP.DHCP_V6_CLIENT_PORT);
1181 }
1182 udp.setDestinationPort(UDP.DHCP_V6_SERVER_PORT);
1183
1184 IPv6 ipv6 = new IPv6();
1185 ipv6.setPayload(udp);
1186 ipv6.setNextHeader(IPv6.PROTOCOL_UDP);
1187 ipv6.setDestinationAddress(SERVER_IP_V6_MCAST.toOctets());
1188 ipv6.setSourceAddress(clientGwAddr.toOctets());
1189
1190 Ethernet eth = new Ethernet();
1191 if (relayLevel > 0) {
1192 eth.setEtherType(Ethernet.TYPE_IPV6)
1193 .setVlanID(vlanId.toShort())
1194 .setSourceMACAddress(OUTER_RELAY_MAC)
1195 .setDestinationMACAddress(MacAddress.valueOf("33:33:00:01:00:02"))
1196 .setPayload(ipv6);
1197 } else {
1198 eth.setEtherType(Ethernet.TYPE_IPV6)
1199 .setVlanID(vlanId.toShort())
1200 .setSourceMACAddress(clientMac)
1201 .setDestinationMACAddress(MacAddress.valueOf("33:33:00:01:00:02"))
1202 .setPayload(ipv6);
1203 }
1204 this.inPacket = new DefaultInboundPacket(clientCp, eth,
1205 ByteBuffer.wrap(eth.serialize()));
1206 }
1207
1208 @Override
1209 public InboundPacket inPacket() {
1210 return this.inPacket;
1211 }
1212 }
1213
1214 /**
1215 * Generates DHCP6 REPLY packet.
1216 */
1217
1218 private class TestDhcp6ReplyPacketContext extends PacketContextAdapter {
1219 private InboundPacket inPacket;
1220
1221 public TestDhcp6ReplyPacketContext(ConnectPoint clientCp, MacAddress clientMac,
1222 VlanId clientVlan, Ip6Address clientGwAddr,
1223 int relayLevel) {
1224 super(0, null, null, false);
1225
1226
1227 DHCP6 dhcp6Payload = new DHCP6();
1228 buildDhcp6Packet(dhcp6Payload, DHCP6.MsgType.REPLY.value(),
1229 IP_FOR_CLIENT_V6,
1230 PREFIX_FOR_CLIENT_V6);
1231 byte[] interfaceId = buildInterfaceId(clientMac, clientCp);
1232 DHCP6 dhcp6 = new DHCP6();
1233 buildRelayMsg(dhcp6, DHCP6.MsgType.RELAY_REPL.value(),
1234 INTERFACE_IP_V6.ipAddress().getIp6Address(),
1235 OUTER_RELAY_IP_V6,
1236 (byte) 0, interfaceId,
1237 dhcp6Payload);
1238
1239 DHCP6 dhcp6Parent = null;
1240 DHCP6 dhcp6Child = dhcp6;
1241 for (int i = 0; i < relayLevel; i++) { // relayLevel 0 : no relay
1242 dhcp6Parent = new DHCP6();
1243
1244 buildRelayMsg(dhcp6Parent, DHCP6.MsgType.RELAY_REPL.value(),
1245 INTERFACE_IP_V6.ipAddress().getIp6Address(),
1246 OUTER_RELAY_IP_V6,
1247 (byte) relayLevel, interfaceId,
1248 dhcp6Child);
1249
1250 dhcp6Child = dhcp6Parent;
1251 }
1252 if (dhcp6Parent != null) {
1253 dhcp6 = dhcp6Parent;
1254 }
1255
1256
1257 UDP udp = new UDP();
1258 udp.setPayload(dhcp6);
1259 udp.setSourcePort(UDP.DHCP_V6_SERVER_PORT);
1260 udp.setDestinationPort(UDP.DHCP_V6_CLIENT_PORT);
1261 IPv6 ipv6 = new IPv6();
1262 ipv6.setPayload(udp);
1263 ipv6.setNextHeader(IPv6.PROTOCOL_UDP);
1264 ipv6.setDestinationAddress(IP_FOR_CLIENT_V6.toOctets());
1265 ipv6.setSourceAddress(SERVER_IP_V6.toOctets());
1266 Ethernet eth = new Ethernet();
1267 if (relayLevel > 0) {
1268 eth.setEtherType(Ethernet.TYPE_IPV6)
1269 .setVlanID(SERVER_VLAN.toShort())
1270 .setSourceMACAddress(SERVER_MAC)
1271 .setDestinationMACAddress(OUTER_RELAY_MAC)
1272 .setPayload(ipv6);
1273 } else {
1274 eth.setEtherType(Ethernet.TYPE_IPV6)
1275 .setVlanID(SERVER_VLAN.toShort())
1276 .setSourceMACAddress(SERVER_MAC)
1277 .setDestinationMACAddress(CLIENT_MAC)
1278 .setPayload(ipv6);
1279 }
1280
1281 this.inPacket = new DefaultInboundPacket(SERVER_CONNECT_POINT, eth,
1282 ByteBuffer.wrap(eth.serialize()));
1283
1284 }
1285
1286 @Override
1287 public InboundPacket inPacket() {
1288 return this.inPacket;
1289 }
1290 }
1291
Yi Tseng7a38f9a2017-06-09 14:36:40 -07001292}