blob: 3d89d7623faa779e243201c9f2be79954401510f [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 Tseng5479fb82017-09-01 17:24:57 -070067import org.onosproject.net.DeviceId;
68import org.onosproject.net.flow.DefaultTrafficSelector;
69import org.onosproject.net.flow.DefaultTrafficTreatment;
70import org.onosproject.net.flow.TrafficSelector;
71import org.onosproject.net.flow.TrafficTreatment;
72import org.onosproject.net.flowobjective.FlowObjectiveService;
73import org.onosproject.net.flowobjective.ForwardingObjective;
74import org.onosproject.net.flowobjective.Objective;
Ray Milkeyfacf2862017-08-03 11:58:29 -070075import org.onosproject.net.intf.Interface;
76import org.onosproject.net.intf.InterfaceServiceAdapter;
Yi Tseng5479fb82017-09-01 17:24:57 -070077import org.onosproject.net.packet.PacketPriority;
Ray Milkey69ec8712017-08-08 13:00:43 -070078import org.onosproject.routeservice.Route;
79import org.onosproject.routeservice.RouteStoreAdapter;
Yi Tseng7a38f9a2017-06-09 14:36:40 -070080import org.onosproject.net.DefaultHost;
81import org.onosproject.net.Host;
82import org.onosproject.net.HostId;
83import org.onosproject.net.HostLocation;
84import org.onosproject.net.config.NetworkConfigRegistry;
85import org.onosproject.net.host.HostDescription;
86import org.onosproject.net.host.HostEvent;
87import org.onosproject.net.host.HostService;
88import org.onosproject.net.host.HostStoreAdapter;
89import org.onosproject.net.host.InterfaceIpAddress;
90import org.onosproject.net.packet.DefaultInboundPacket;
91import org.onosproject.net.packet.InboundPacket;
92import org.onosproject.net.packet.OutboundPacket;
93import org.onosproject.net.packet.PacketContext;
94import org.onosproject.net.packet.PacketContextAdapter;
95import org.onosproject.net.packet.PacketProcessor;
96import org.onosproject.net.packet.PacketServiceAdapter;
97import org.onosproject.net.provider.ProviderId;
98import org.onosproject.store.StoreDelegate;
99import org.osgi.service.component.ComponentContext;
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000100import org.onlab.packet.DHCP6;
101import org.onlab.packet.IPv6;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700102
103import java.nio.ByteBuffer;
104import java.util.Collection;
105import java.util.Dictionary;
106import java.util.List;
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000107import java.util.ArrayList;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700108import java.util.Map;
109import java.util.Optional;
110import java.util.Set;
111import java.util.stream.Collectors;
112
113import static org.easymock.EasyMock.*;
114import static org.junit.Assert.*;
Yi Tseng5479fb82017-09-01 17:24:57 -0700115import static org.onosproject.dhcprelay.DhcpRelayManager.DHCP_RELAY_APP;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700116
117public class DhcpRelayManagerTest {
Yi Tseng5479fb82017-09-01 17:24:57 -0700118 private static final String CONFIG_FILE_PATH = "dhcp-relay.json";
119 private static final DeviceId DEV_1_ID = DeviceId.deviceId("of:0000000000000001");
120 private static final DeviceId DEV_2_ID = DeviceId.deviceId("of:0000000000000002");
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700121 // Ip address for interfaces
122 private static final InterfaceIpAddress INTERFACE_IP = InterfaceIpAddress.valueOf("10.0.3.254/32");
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000123 private static final InterfaceIpAddress INTERFACE_IP_V6 = InterfaceIpAddress.valueOf("2001:db8:1::254/128");
124 private static final List<InterfaceIpAddress> INTERFACE_IPS = ImmutableList.of(INTERFACE_IP, INTERFACE_IP_V6);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700125
126 // DHCP client (will send without option 82)
127 private static final Ip4Address IP_FOR_CLIENT = Ip4Address.valueOf("10.0.0.1");
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000128 private static final Ip6Address IP_FOR_CLIENT_V6 = Ip6Address.valueOf("2001:db8:1::110");
129 private static final IpPrefix PREFIX_FOR_CLIENT_V6 = IpPrefix.valueOf("2001:db8:10::/56");
130 private static final IpPrefix PREFIX_FOR_ZERO = IpPrefix.valueOf("::/0");
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700131 private static final MacAddress CLIENT_MAC = MacAddress.valueOf("00:00:00:00:00:01");
132 private static final VlanId CLIENT_VLAN = VlanId.vlanId("100");
133 private static final ConnectPoint CLIENT_CP = ConnectPoint.deviceConnectPoint("of:0000000000000001/1");
134 private static final MacAddress CLIENT_IFACE_MAC = MacAddress.valueOf("00:00:00:00:11:01");
135 private static final Interface CLIENT_INTERFACE = new Interface("C1",
136 CLIENT_CP,
137 INTERFACE_IPS,
138 CLIENT_IFACE_MAC,
139 CLIENT_VLAN);
140
141 // DHCP client 2 (will send with option 82, so the vlan should equals to vlan from server)
142 private static final MacAddress CLIENT2_MAC = MacAddress.valueOf("00:00:00:00:00:01");
143 private static final VlanId CLIENT2_VLAN = VlanId.NONE;
144 private static final ConnectPoint CLIENT2_CP = ConnectPoint.deviceConnectPoint("of:0000000000000001/2");
145 private static final MacAddress CLIENT2_IFACE_MAC = MacAddress.valueOf("00:00:00:00:11:01");
146 private static final Interface CLIENT2_INTERFACE = new Interface("C2",
147 CLIENT2_CP,
148 INTERFACE_IPS,
149 CLIENT2_IFACE_MAC,
150 CLIENT2_VLAN);
151
152 // Outer relay information
153 private static final Ip4Address OUTER_RELAY_IP = Ip4Address.valueOf("10.0.5.253");
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000154 private static final Ip6Address OUTER_RELAY_IP_V6 = Ip6Address.valueOf("2001:db8:1::4");
155 private static final Set<IpAddress> OUTER_RELAY_IPS = ImmutableSet.of(OUTER_RELAY_IP, OUTER_RELAY_IP_V6);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700156 private static final MacAddress OUTER_RELAY_MAC = MacAddress.valueOf("00:01:02:03:04:05");
157 private static final VlanId OUTER_RELAY_VLAN = VlanId.NONE;
158 private static final ConnectPoint OUTER_RELAY_CP = ConnectPoint.deviceConnectPoint("of:0000000000000001/2");
159 private static final HostLocation OUTER_REPLAY_HL = new HostLocation(OUTER_RELAY_CP, 0);
160 private static final HostId OUTER_RELAY_HOST_ID = HostId.hostId(OUTER_RELAY_MAC, OUTER_RELAY_VLAN);
161 private static final Host OUTER_RELAY_HOST = new DefaultHost(DhcpRelayManager.PROVIDER_ID,
162 OUTER_RELAY_HOST_ID,
163 OUTER_RELAY_MAC,
164 OUTER_RELAY_VLAN,
165 OUTER_REPLAY_HL,
166 OUTER_RELAY_IPS);
167
168 // DHCP Server
169 private static final MacAddress SERVER_MAC = MacAddress.valueOf("00:00:00:00:00:01");
170 private static final VlanId SERVER_VLAN = VlanId.NONE;
171 private static final ConnectPoint SERVER_CONNECT_POINT =
172 ConnectPoint.deviceConnectPoint("of:0000000000000001/5");
173 private static final HostLocation SERVER_LOCATION =
174 new HostLocation(SERVER_CONNECT_POINT, 0);
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000175 private static final Ip4Address GATEWAY_IP = Ip4Address.valueOf("10.0.5.253");
176 private static final Ip6Address GATEWAY_IP_V6 = Ip6Address.valueOf("2000::105:253");
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700177 private static final Ip4Address SERVER_IP = Ip4Address.valueOf("10.0.3.253");
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000178 private static final Ip6Address SERVER_IP_V6 = Ip6Address.valueOf("2000::103:253");
179 private static final Ip6Address SERVER_IP_V6_MCAST = Ip6Address.valueOf("ff02::1:2");
180 private static final Set<IpAddress> DHCP_SERVER_IPS = ImmutableSet.of(SERVER_IP, SERVER_IP_V6);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700181 private static final HostId SERVER_HOST_ID = HostId.hostId(SERVER_MAC, SERVER_VLAN);
182 private static final Host SERVER_HOST = new DefaultHost(DhcpRelayManager.PROVIDER_ID,
183 SERVER_HOST_ID,
184 SERVER_MAC,
185 SERVER_VLAN,
186 SERVER_LOCATION,
187 DHCP_SERVER_IPS);
188 private static final MacAddress SERVER_IFACE_MAC = MacAddress.valueOf("00:00:00:00:00:01");
189 private static final Interface SERVER_INTERFACE = new Interface("SERVER",
190 SERVER_CONNECT_POINT,
191 INTERFACE_IPS,
192 SERVER_IFACE_MAC,
193 SERVER_VLAN);
194
Yi Tseng4fa05832017-08-17 13:08:31 -0700195 // Relay agent config
196 private static final Ip4Address RELAY_AGENT_IP = Ip4Address.valueOf("10.0.4.254");
197
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700198 // Components
199 private static final ApplicationId APP_ID = TestApplicationId.create(DhcpRelayManager.DHCP_RELAY_APP);
Yi Tsenge72fbb52017-08-02 15:03:31 -0700200 private static final DefaultDhcpRelayConfig CONFIG = new MockDefaultDhcpRelayConfig();
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000201 private static final IndirectDhcpRelayConfig CONFIG_INDIRECT = new MockIndirectDhcpRelayConfig();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700202 private static final Set<Interface> INTERFACES = ImmutableSet.of(
203 CLIENT_INTERFACE,
204 CLIENT2_INTERFACE,
205 SERVER_INTERFACE
206 );
Yi Tseng2cf59912017-08-24 14:47:34 -0700207 private static final String NON_ONOS_CID = "Non-ONOS circuit ID";
Yi Tseng5479fb82017-09-01 17:24:57 -0700208 private static final VlanId IGNORED_VLAN = VlanId.vlanId("100");
209 private static final int IGNORE_CONTROL_PRIORITY = PacketPriority.CONTROL.priorityValue() + 1000;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700210
211 private DhcpRelayManager manager;
212 private MockPacketService packetService;
213 private MockHostStore mockHostStore;
214 private MockRouteStore mockRouteStore;
215 private MockDhcpRelayStore mockDhcpRelayStore;
216
217 @Before
218 public void setup() {
219 manager = new DhcpRelayManager();
220 manager.cfgService = createNiceMock(NetworkConfigRegistry.class);
221
Yi Tsenge72fbb52017-08-02 15:03:31 -0700222 expect(manager.cfgService.getConfig(APP_ID, DefaultDhcpRelayConfig.class))
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700223 .andReturn(CONFIG)
224 .anyTimes();
225
Yi Tsenge72fbb52017-08-02 15:03:31 -0700226 // TODO: add indirect test
227 expect(manager.cfgService.getConfig(APP_ID, IndirectDhcpRelayConfig.class))
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000228 .andReturn(CONFIG_INDIRECT)
Yi Tsenge72fbb52017-08-02 15:03:31 -0700229 .anyTimes();
230
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700231 manager.coreService = createNiceMock(CoreService.class);
232 expect(manager.coreService.registerApplication(anyString()))
233 .andReturn(APP_ID).anyTimes();
234
235 manager.hostService = createNiceMock(HostService.class);
Yi Tseng4fa05832017-08-17 13:08:31 -0700236 expect(manager.hostService.getHostsByIp(anyObject())).andReturn(ImmutableSet.of(SERVER_HOST)).anyTimes();
237 expect(manager.hostService.getHost(OUTER_RELAY_HOST_ID)).andReturn(OUTER_RELAY_HOST).anyTimes();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700238
239 packetService = new MockPacketService();
240 manager.packetService = packetService;
241 manager.compCfgService = createNiceMock(ComponentConfigService.class);
242
243 mockHostStore = new MockHostStore();
244 mockRouteStore = new MockRouteStore();
245 mockDhcpRelayStore = new MockDhcpRelayStore();
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700246 manager.dhcpRelayStore = mockDhcpRelayStore;
247
248 manager.interfaceService = new MockInterfaceService();
Yi Tseng5479fb82017-09-01 17:24:57 -0700249 manager.flowObjectiveService = EasyMock.niceMock(FlowObjectiveService.class);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700250
Yi Tseng51301292017-07-28 13:02:59 -0700251 Dhcp4HandlerImpl v4Handler = new Dhcp4HandlerImpl();
252 v4Handler.dhcpRelayStore = mockDhcpRelayStore;
253 v4Handler.hostService = manager.hostService;
254 v4Handler.hostStore = mockHostStore;
255 v4Handler.interfaceService = manager.interfaceService;
256 v4Handler.packetService = manager.packetService;
257 v4Handler.routeStore = mockRouteStore;
258 manager.v4Handler = v4Handler;
259
260 // TODO: initialize v6 handler.
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000261 //DhcpHandler v6Handler = createNiceMock(DhcpHandler.class);
262 Dhcp6HandlerImpl v6Handler = new Dhcp6HandlerImpl();
263 v6Handler.dhcpRelayStore = mockDhcpRelayStore;
264 v6Handler.hostService = manager.hostService;
265 v6Handler.hostStore = mockHostStore;
266 v6Handler.interfaceService = manager.interfaceService;
267 v6Handler.packetService = manager.packetService;
268 v6Handler.routeStore = mockRouteStore;
Yi Tsenge72fbb52017-08-02 15:03:31 -0700269 manager.v6Handler = v6Handler;
270
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700271 // properties
272 Dictionary<String, Object> dictionary = createNiceMock(Dictionary.class);
273 expect(dictionary.get("arpEnabled")).andReturn(true).anyTimes();
274 ComponentContext context = createNiceMock(ComponentContext.class);
275 expect(context.getProperties()).andReturn(dictionary).anyTimes();
276
277 EasyMock.replay(manager.cfgService, manager.coreService, manager.hostService,
278 manager.compCfgService, dictionary, context);
279 manager.activate(context);
280 }
281
282 @After
283 public void tearDown() {
284 manager.deactivate();
285 }
286
287 /**
288 * Relay a DHCP packet without option 82.
289 * Should add new host to host store after dhcp ack.
290 */
291 @Test
292 public void relayDhcpWithoutAgentInfo() {
293 // send request
294 packetService.processPacket(new TestDhcpRequestPacketContext(CLIENT_MAC,
295 CLIENT_VLAN,
296 CLIENT_CP,
297 INTERFACE_IP.ipAddress().getIp4Address(),
298 false));
299
300 Set<Host> hosts = ImmutableSet.copyOf(mockHostStore.getHosts());
301 assertEquals(0, hosts.size());
302 assertEquals(0, mockRouteStore.routes.size());
303
304 // send ack
305 packetService.processPacket(new TestDhcpAckPacketContext(CLIENT_CP, CLIENT_MAC,
306 CLIENT_VLAN, INTERFACE_IP.ipAddress().getIp4Address(),
307 false));
308 hosts = ImmutableSet.copyOf(mockHostStore.getHosts());
309 assertEquals(1, hosts.size());
310 assertEquals(0, mockRouteStore.routes.size());
311
312 Host host = hosts.iterator().next();
313 assertEquals(CLIENT_MAC, host.mac());
314 assertEquals(CLIENT_VLAN, host.vlan());
315 assertEquals(CLIENT_CP.deviceId(), host.location().elementId());
316 assertEquals(CLIENT_CP.port(), host.location().port());
317 assertEquals(1, host.ipAddresses().size());
318 assertEquals(IP_FOR_CLIENT, host.ipAddresses().iterator().next());
319 assertEquals(HostId.hostId(CLIENT_MAC, CLIENT_VLAN), host.id());
320 }
321
322 /**
323 * Relay a DHCP packet with option 82 (Indirectly connected host).
324 */
325 @Test
326 public void relayDhcpWithAgentInfo() {
327 // Assume outer dhcp relay agent exists in store already
328 // send request
329 packetService.processPacket(new TestDhcpRequestPacketContext(CLIENT2_MAC,
330 CLIENT2_VLAN,
331 CLIENT2_CP,
332 INTERFACE_IP.ipAddress().getIp4Address(),
333 true));
334
335 Set<Host> hosts = ImmutableSet.copyOf(mockHostStore.getHosts());
336 assertEquals(0, hosts.size());
337 assertEquals(0, mockRouteStore.routes.size());
338
339 // send ack
340 packetService.processPacket(new TestDhcpAckPacketContext(CLIENT2_CP,
341 CLIENT2_MAC,
342 CLIENT2_VLAN,
343 INTERFACE_IP.ipAddress().getIp4Address(),
344 true));
345
346 hosts = ImmutableSet.copyOf(mockHostStore.getHosts());
347 assertEquals(0, hosts.size());
348 assertEquals(1, mockRouteStore.routes.size());
349
350 Route route = mockRouteStore.routes.get(0);
351 assertEquals(OUTER_RELAY_IP, route.nextHop());
352 assertEquals(IP_FOR_CLIENT.toIpPrefix(), route.prefix());
353 assertEquals(Route.Source.STATIC, route.source());
354 }
355
356 @Test
Yi Tseng4fa05832017-08-17 13:08:31 -0700357 public void testWithRelayAgentConfig() throws DeserializationException {
358 manager.v4Handler
359 .setDefaultDhcpServerConfigs(ImmutableList.of(new MockDhcpServerConfig(RELAY_AGENT_IP)));
Yi Tseng4ec727d2017-08-31 11:21:00 -0700360 manager.v4Handler
361 .setIndirectDhcpServerConfigs(ImmutableList.of(new MockDhcpServerConfig(RELAY_AGENT_IP)));
Yi Tseng4fa05832017-08-17 13:08:31 -0700362 packetService.processPacket(new TestDhcpRequestPacketContext(CLIENT2_MAC,
363 CLIENT2_VLAN,
364 CLIENT2_CP,
365 INTERFACE_IP.ipAddress().getIp4Address(),
366 true));
367 OutboundPacket outPacket = packetService.emittedPacket;
368 byte[] outData = outPacket.data().array();
369 Ethernet eth = Ethernet.deserializer().deserialize(outData, 0, outData.length);
370 IPv4 ip = (IPv4) eth.getPayload();
371 UDP udp = (UDP) ip.getPayload();
372 DHCP dhcp = (DHCP) udp.getPayload();
373 assertEquals(RELAY_AGENT_IP.toInt(), dhcp.getGatewayIPAddress());
374 }
375
376 @Test
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700377 public void testArpRequest() throws Exception {
378 packetService.processPacket(new TestArpRequestPacketContext(CLIENT_INTERFACE));
Ray Milkeybd52a052017-08-23 15:23:50 -0700379 OutboundPacket outboundPacket = packetService.emittedPacket;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700380 byte[] outPacketData = outboundPacket.data().array();
381 Ethernet eth = Ethernet.deserializer().deserialize(outPacketData, 0, outPacketData.length);
382
383 assertEquals(eth.getEtherType(), Ethernet.TYPE_ARP);
384 ARP arp = (ARP) eth.getPayload();
385 assertArrayEquals(arp.getSenderHardwareAddress(), CLIENT_INTERFACE.mac().toBytes());
386 }
387
Yi Tseng5479fb82017-09-01 17:24:57 -0700388 /**
389 * Ignores specific vlans from specific devices if config.
390 *
391 * @throws Exception the exception from this test
392 */
393 @Test
394 public void testIgnoreVlan() throws Exception {
395 ObjectMapper om = new ObjectMapper();
396 JsonNode json = om.readTree(Resources.getResource(CONFIG_FILE_PATH));
397 IgnoreDhcpConfig config = new IgnoreDhcpConfig();
398 json = json.path("apps").path(DHCP_RELAY_APP).path(IgnoreDhcpConfig.KEY);
399 config.init(APP_ID, IgnoreDhcpConfig.KEY, json, om, null);
400
401 Capture<Objective> capturedFromDev1 = newCapture(CaptureType.ALL);
402 manager.flowObjectiveService.apply(eq(DEV_1_ID), capture(capturedFromDev1));
403 expectLastCall().times(2);
404 Capture<Objective> capturedFromDev2 = newCapture(CaptureType.ALL);
405 manager.flowObjectiveService.apply(eq(DEV_2_ID), capture(capturedFromDev2));
406 expectLastCall().times(2);
407 replay(manager.flowObjectiveService);
408 manager.updateConfig(config);
409 verify(manager.flowObjectiveService);
410
411 List<Objective> objectivesFromDev1 = capturedFromDev1.getValues();
412 List<Objective> objectivesFromDev2 = capturedFromDev2.getValues();
413
414 assertTrue(objectivesFromDev1.containsAll(objectivesFromDev2));
415 assertTrue(objectivesFromDev2.containsAll(objectivesFromDev1));
416 TrafficTreatment dropTreatment = DefaultTrafficTreatment.emptyTreatment();
417 dropTreatment.clearedDeferred();
418
419 for (int index = 0; index < objectivesFromDev1.size(); index++) {
420 TrafficSelector selector =
421 DefaultTrafficSelector.builder(DhcpRelayManager.DHCP_SELECTORS.get(index))
422 .matchVlanId(IGNORED_VLAN)
423 .build();
424 ForwardingObjective fwd = (ForwardingObjective) objectivesFromDev1.get(index);
425 assertEquals(selector, fwd.selector());
426 assertEquals(dropTreatment, fwd.treatment());
427 assertEquals(IGNORE_CONTROL_PRIORITY, fwd.priority());
428 assertEquals(ForwardingObjective.Flag.VERSATILE, fwd.flag());
429 assertEquals(Objective.Operation.ADD, fwd.op());
430 }
431
432 assertEquals(2, manager.ignoredVlans.size());
433 }
434
435 /**
436 * "IgnoreVlan" policy should be removed when the config removed.
437 */
438 @Test
439 public void testRemoveIgnoreVlan() {
440 manager.ignoredVlans.put(DEV_1_ID, IGNORED_VLAN);
441 manager.ignoredVlans.put(DEV_2_ID, IGNORED_VLAN);
442 IgnoreDhcpConfig config = new IgnoreDhcpConfig();
443
444 Capture<Objective> capturedFromDev1 = newCapture(CaptureType.ALL);
445 manager.flowObjectiveService.apply(eq(DEV_1_ID), capture(capturedFromDev1));
446 expectLastCall().times(2);
447 Capture<Objective> capturedFromDev2 = newCapture(CaptureType.ALL);
448 manager.flowObjectiveService.apply(eq(DEV_2_ID), capture(capturedFromDev2));
449 expectLastCall().times(2);
450 replay(manager.flowObjectiveService);
451 manager.removeConfig(config);
452 verify(manager.flowObjectiveService);
453
454 List<Objective> objectivesFromDev1 = capturedFromDev1.getValues();
455 List<Objective> objectivesFromDev2 = capturedFromDev2.getValues();
456
457 assertTrue(objectivesFromDev1.containsAll(objectivesFromDev2));
458 assertTrue(objectivesFromDev2.containsAll(objectivesFromDev1));
459 TrafficTreatment dropTreatment = DefaultTrafficTreatment.emptyTreatment();
460 dropTreatment.clearedDeferred();
461
462 for (int index = 0; index < objectivesFromDev1.size(); index++) {
463 TrafficSelector selector =
464 DefaultTrafficSelector.builder(DhcpRelayManager.DHCP_SELECTORS.get(index))
465 .matchVlanId(IGNORED_VLAN)
466 .build();
467 ForwardingObjective fwd = (ForwardingObjective) objectivesFromDev1.get(index);
468 assertEquals(selector, fwd.selector());
469 assertEquals(dropTreatment, fwd.treatment());
470 assertEquals(IGNORE_CONTROL_PRIORITY, fwd.priority());
471 assertEquals(ForwardingObjective.Flag.VERSATILE, fwd.flag());
472 assertEquals(Objective.Operation.REMOVE, fwd.op());
473 }
474 assertEquals(0, manager.ignoredVlans.size());
475 }
476
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000477 /**
478 * Relay a DHCP6 packet without relay option
479 * Note: Should add new host to host store after dhcp ack.
480 */
481 @Test
482 public void relayDhcp6WithoutAgentInfo() {
483 // send request
484 packetService.processPacket(new TestDhcp6RequestPacketContext(CLIENT_MAC,
485 VlanId.NONE,
486 CLIENT_CP,
487 INTERFACE_IP_V6.ipAddress().getIp6Address(),
488 0));
489
490 Set<Host> hosts = ImmutableSet.copyOf(mockHostStore.getHosts());
491 assertEquals(0, hosts.size());
492 assertEquals(0, mockRouteStore.routes.size());
493
494 // send reply
495 packetService.processPacket(new TestDhcp6ReplyPacketContext(CLIENT_CP, CLIENT_MAC,
496 CLIENT_VLAN,
497 INTERFACE_IP_V6.ipAddress().getIp6Address(),
498 0));
499 hosts = ImmutableSet.copyOf(mockHostStore.getHosts());
500 assertEquals(1, hosts.size());
501 assertEquals(0, mockRouteStore.routes.size());
502
503 Host host = hosts.iterator().next();
504 assertEquals(CLIENT_MAC, host.mac());
505 assertEquals(CLIENT_VLAN, host.vlan());
506 assertEquals(CLIENT_CP.deviceId(), host.location().elementId());
507 assertEquals(CLIENT_CP.port(), host.location().port());
508 assertEquals(1, host.ipAddresses().size());
509 assertEquals(IP_FOR_CLIENT_V6, host.ipAddresses().iterator().next());
510 assertEquals(HostId.hostId(CLIENT_MAC, CLIENT_VLAN), host.id());
511 }
512
513 /**
514 * Relay a DHCP6 packet with Relay Message opion (Indirectly connected host).
515 */
516 @Test
517 public void relayDhcp6WithAgentInfo() {
518 // Assume outer dhcp6 relay agent exists in store already
519 // send request
520 packetService.processPacket(new TestDhcp6RequestPacketContext(CLIENT2_MAC,
521 CLIENT2_VLAN,
522 CLIENT2_CP,
523 INTERFACE_IP_V6.ipAddress().getIp6Address(),
524 1));
525
526 Set<Host> hosts = ImmutableSet.copyOf(mockHostStore.getHosts());
527 assertEquals(0, hosts.size());
528 assertEquals(0, mockRouteStore.routes.size());
529
530 // send reply
531 packetService.processPacket(new TestDhcp6ReplyPacketContext(CLIENT2_CP,
532 CLIENT2_MAC,
533 CLIENT2_VLAN,
534 INTERFACE_IP_V6.ipAddress().getIp6Address(),
535 1));
536
537 hosts = ImmutableSet.copyOf(mockHostStore.getHosts());
538 assertEquals(0, hosts.size());
539 assertEquals(2, mockRouteStore.routes.size()); // ipAddress and prefix
540
541 Route route = mockRouteStore.routes.get(0);
542 assertEquals(OUTER_RELAY_IP_V6, route.nextHop());
543 assertEquals(IP_FOR_CLIENT_V6.toIpPrefix(), route.prefix());
544 assertEquals(Route.Source.STATIC, route.source());
545 }
Yi Tsenge72fbb52017-08-02 15:03:31 -0700546 private static class MockDefaultDhcpRelayConfig extends DefaultDhcpRelayConfig {
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700547 @Override
548 public boolean isValid() {
549 return true;
550 }
551
552 @Override
Yi Tsenge72fbb52017-08-02 15:03:31 -0700553 public List<DhcpServerConfig> dhcpServerConfigs() {
Yi Tseng4fa05832017-08-17 13:08:31 -0700554 return ImmutableList.of(new MockDhcpServerConfig(null));
Yi Tsenge72fbb52017-08-02 15:03:31 -0700555 }
556 }
557
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000558 private static class MockIndirectDhcpRelayConfig extends IndirectDhcpRelayConfig {
559 @Override
560 public boolean isValid() {
561 return true;
562 }
563
564 @Override
565 public List<DhcpServerConfig> dhcpServerConfigs() {
566 return ImmutableList.of(new MockDhcpServerConfig(null));
567 }
568 }
569
Yi Tsenge72fbb52017-08-02 15:03:31 -0700570 private static class MockDhcpServerConfig extends DhcpServerConfig {
Yi Tseng4fa05832017-08-17 13:08:31 -0700571 Ip4Address relayAgentIp;
572
573 /**
574 * Create mocked version DHCP server config.
575 *
576 * @param relayAgentIp the relay agent Ip config; null if we don't need it
577 */
578 public MockDhcpServerConfig(Ip4Address relayAgentIp) {
579 this.relayAgentIp = relayAgentIp;
580 }
581
582 @Override
583 public Optional<Ip4Address> getRelayAgentIp4() {
584 return Optional.ofNullable(relayAgentIp);
585 }
586
Yi Tsenge72fbb52017-08-02 15:03:31 -0700587 @Override
588 public Optional<ConnectPoint> getDhcpServerConnectPoint() {
589 return Optional.of(SERVER_CONNECT_POINT);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700590 }
591
Yi Tsenge72fbb52017-08-02 15:03:31 -0700592 @Override
593 public Optional<Ip4Address> getDhcpServerIp4() {
594 return Optional.of(SERVER_IP);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700595 }
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000596
597 @Override
598 public Optional<Ip4Address> getDhcpGatewayIp4() {
599 return Optional.of(GATEWAY_IP);
600 }
601
602 @Override
603 public Optional<Ip6Address> getDhcpServerIp6() {
604 return Optional.of(SERVER_IP_V6);
605 }
606
607 @Override
608 public Optional<Ip6Address> getDhcpGatewayIp6() {
609 return Optional.of(GATEWAY_IP_V6);
610 }
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700611 }
612
613 private class MockHostStore extends HostStoreAdapter {
614
615 private final Map<HostId, HostDescription> hosts = Maps.newHashMap();
616
617 @Override
618 public HostEvent createOrUpdateHost(ProviderId providerId, HostId hostId,
619 HostDescription hostDescription,
620 boolean replaceIps) {
621 hosts.put(hostId, hostDescription);
622
623 // not necessary to return host event in this test.
624 return null;
625 }
626
627 public HostDescription hostDesc(HostId hostId) {
628 return hosts.get(hostId);
629 }
630
631 @Override
632 public Iterable<Host> getHosts() {
633 return hosts.values().stream()
634 .map(hd -> new DefaultHost(DhcpRelayManager.PROVIDER_ID,
635 HostId.hostId(hd.hwAddress(), hd.vlan()),
636 hd.hwAddress(),
637 hd.vlan(), hd.locations(),
638 hd.ipAddress(), false))
639 .collect(Collectors.toList());
640 }
641 }
642
643 private class MockRouteStore extends RouteStoreAdapter {
644 private List<Route> routes = Lists.newArrayList();
645
646 @Override
647 public void updateRoute(Route route) {
648 routes.add(route);
649 }
650 }
651
652 private class MockInterfaceService extends InterfaceServiceAdapter {
653
654 @Override
655 public Set<Interface> getInterfaces() {
656 return INTERFACES;
657 }
658
659 @Override
660 public Set<Interface> getInterfacesByIp(IpAddress ip) {
661 return INTERFACES.stream()
662 .filter(iface -> {
663 return iface.ipAddressesList().stream()
664 .anyMatch(ifaceIp -> ifaceIp.ipAddress().equals(ip));
665 })
666 .collect(Collectors.toSet());
667 }
668
669 @Override
670 public Set<Interface> getInterfacesByPort(ConnectPoint port) {
671 return INTERFACES.stream()
672 .filter(iface -> iface.connectPoint().equals(port))
673 .collect(Collectors.toSet());
674 }
675 }
676
677 private class MockDhcpRelayStore implements DhcpRelayStore {
678 StoreDelegate<DhcpRelayStoreEvent> delegate;
679 private Map<HostId, DhcpRecord> records = Maps.newHashMap();
680
681 @Override
682 public void updateDhcpRecord(HostId hostId, DhcpRecord dhcpRecord) {
683 records.put(hostId, dhcpRecord);
684 DhcpRelayStoreEvent event = new DhcpRelayStoreEvent(DhcpRelayStoreEvent.Type.UPDATED,
685 dhcpRecord);
686 if (delegate != null) {
687 delegate.notify(event);
688 }
689 }
690
691 @Override
692 public Optional<DhcpRecord> getDhcpRecord(HostId hostId) {
693 return Optional.ofNullable(records.get(hostId));
694 }
695
696 @Override
697 public Collection<DhcpRecord> getDhcpRecords() {
698 return records.values();
699 }
700
701 @Override
702 public Optional<DhcpRecord> removeDhcpRecord(HostId hostId) {
703 DhcpRecord dhcpRecord = records.remove(hostId);
704 if (dhcpRecord != null) {
705 DhcpRelayStoreEvent event = new DhcpRelayStoreEvent(DhcpRelayStoreEvent.Type.REMOVED,
706 dhcpRecord);
707 if (delegate != null) {
708 delegate.notify(event);
709 }
710 }
711 return Optional.ofNullable(dhcpRecord);
712 }
713
714 @Override
715 public void setDelegate(StoreDelegate<DhcpRelayStoreEvent> delegate) {
716 this.delegate = delegate;
717 }
718
719 @Override
720 public void unsetDelegate(StoreDelegate<DhcpRelayStoreEvent> delegate) {
721 this.delegate = null;
722 }
723
724 @Override
725 public boolean hasDelegate() {
726 return this.delegate != null;
727 }
728 }
729
730 private class MockPacketService extends PacketServiceAdapter {
731 Set<PacketProcessor> packetProcessors = Sets.newHashSet();
Ray Milkeybd52a052017-08-23 15:23:50 -0700732 OutboundPacket emittedPacket;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700733
734 @Override
735 public void addProcessor(PacketProcessor processor, int priority) {
736 packetProcessors.add(processor);
737 }
738
739 public void processPacket(PacketContext packetContext) {
740 packetProcessors.forEach(p -> p.process(packetContext));
741 }
742
743 @Override
744 public void emit(OutboundPacket packet) {
Ray Milkeybd52a052017-08-23 15:23:50 -0700745 this.emittedPacket = packet;
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700746 }
747 }
748
749
750
751 /**
752 * Generates DHCP REQUEST packet.
753 */
754 private class TestDhcpRequestPacketContext extends PacketContextAdapter {
755
756
757 private InboundPacket inPacket;
758
759 public TestDhcpRequestPacketContext(MacAddress clientMac, VlanId vlanId,
760 ConnectPoint clientCp,
761 Ip4Address clientGwAddr,
762 boolean withNonOnosRelayInfo) {
763 super(0, null, null, false);
764 byte[] dhcpMsgType = new byte[1];
765 dhcpMsgType[0] = (byte) DHCP.MsgType.DHCPREQUEST.getValue();
766
767 DhcpOption dhcpOption = new DhcpOption();
768 dhcpOption.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue());
769 dhcpOption.setData(dhcpMsgType);
770 dhcpOption.setLength((byte) 1);
771 DhcpOption endOption = new DhcpOption();
772 endOption.setCode(DHCP.DHCPOptionCode.OptionCode_END.getValue());
773
774 DHCP dhcp = new DHCP();
775 dhcp.setHardwareType(DHCP.HWTYPE_ETHERNET);
776 dhcp.setHardwareAddressLength((byte) 6);
777 dhcp.setClientHardwareAddress(clientMac.toBytes());
778 if (withNonOnosRelayInfo) {
779 DhcpRelayAgentOption relayOption = new DhcpRelayAgentOption();
780 DhcpOption circuitIdOption = new DhcpOption();
781 CircuitId circuitId = new CircuitId("Custom option", VlanId.NONE);
782 byte[] cid = circuitId.serialize();
783 circuitIdOption.setCode(DhcpRelayAgentOption.RelayAgentInfoOptions.CIRCUIT_ID.getValue());
784 circuitIdOption.setLength((byte) cid.length);
785 circuitIdOption.setData(cid);
786 relayOption.setCode(DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue());
787 relayOption.addSubOption(circuitIdOption);
788 dhcp.setOptions(ImmutableList.of(dhcpOption, relayOption, endOption));
789 dhcp.setGatewayIPAddress(OUTER_RELAY_IP.getIp4Address().toInt());
790 } else {
791 dhcp.setOptions(ImmutableList.of(dhcpOption, endOption));
792 }
793
794
795 UDP udp = new UDP();
796 udp.setPayload(dhcp);
797 udp.setSourcePort(UDP.DHCP_CLIENT_PORT);
798 udp.setDestinationPort(UDP.DHCP_SERVER_PORT);
799
800 IPv4 ipv4 = new IPv4();
801 ipv4.setPayload(udp);
802 ipv4.setDestinationAddress(SERVER_IP.toInt());
803 ipv4.setSourceAddress(clientGwAddr.toInt());
804
805 Ethernet eth = new Ethernet();
806 if (withNonOnosRelayInfo) {
807 eth.setEtherType(Ethernet.TYPE_IPV4)
808 .setVlanID(vlanId.toShort())
809 .setSourceMACAddress(OUTER_RELAY_MAC)
810 .setDestinationMACAddress(MacAddress.BROADCAST)
811 .setPayload(ipv4);
812 } else {
813 eth.setEtherType(Ethernet.TYPE_IPV4)
814 .setVlanID(vlanId.toShort())
815 .setSourceMACAddress(clientMac)
816 .setDestinationMACAddress(MacAddress.BROADCAST)
817 .setPayload(ipv4);
818 }
819
820 this.inPacket = new DefaultInboundPacket(clientCp, eth,
821 ByteBuffer.wrap(eth.serialize()));
822 }
823
824 @Override
825 public InboundPacket inPacket() {
826 return this.inPacket;
827 }
828 }
829
830 /**
831 * Generates DHCP ACK packet.
832 */
833 private class TestDhcpAckPacketContext extends PacketContextAdapter {
834 private InboundPacket inPacket;
835
836 public TestDhcpAckPacketContext(ConnectPoint clientCp, MacAddress clientMac,
837 VlanId clientVlan, Ip4Address clientGwAddr,
838 boolean withNonOnosRelayInfo) {
839 super(0, null, null, false);
840
841 byte[] dhcpMsgType = new byte[1];
842 dhcpMsgType[0] = (byte) DHCP.MsgType.DHCPACK.getValue();
843
844 DhcpOption dhcpOption = new DhcpOption();
845 dhcpOption.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue());
846 dhcpOption.setData(dhcpMsgType);
847 dhcpOption.setLength((byte) 1);
848
849 DhcpOption endOption = new DhcpOption();
850 endOption.setCode(DHCP.DHCPOptionCode.OptionCode_END.getValue());
851
852 DHCP dhcp = new DHCP();
853 if (withNonOnosRelayInfo) {
854 DhcpRelayAgentOption relayOption = new DhcpRelayAgentOption();
855 DhcpOption circuitIdOption = new DhcpOption();
Yi Tseng2cf59912017-08-24 14:47:34 -0700856 String circuitId = NON_ONOS_CID;
857 byte[] cid = circuitId.getBytes(Charsets.US_ASCII);
Yi Tseng7a38f9a2017-06-09 14:36:40 -0700858 circuitIdOption.setCode(DhcpRelayAgentOption.RelayAgentInfoOptions.CIRCUIT_ID.getValue());
859 circuitIdOption.setLength((byte) cid.length);
860 circuitIdOption.setData(cid);
861 relayOption.setCode(DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue());
862 relayOption.addSubOption(circuitIdOption);
863 dhcp.setOptions(ImmutableList.of(dhcpOption, relayOption, endOption));
864 dhcp.setGatewayIPAddress(OUTER_RELAY_IP.getIp4Address().toInt());
865 } else {
866 CircuitId cid = new CircuitId(clientCp.toString(), clientVlan);
867 byte[] circuitId = cid.serialize();
868 DhcpOption circuitIdSubOption = new DhcpOption();
869 circuitIdSubOption.setCode(DhcpRelayAgentOption.RelayAgentInfoOptions.CIRCUIT_ID.getValue());
870 circuitIdSubOption.setData(circuitId);
871 circuitIdSubOption.setLength((byte) circuitId.length);
872
873 DhcpRelayAgentOption relayInfoOption = new DhcpRelayAgentOption();
874 relayInfoOption.setCode(DHCP.DHCPOptionCode.OptionCode_CircuitID.getValue());
875 relayInfoOption.addSubOption(circuitIdSubOption);
876 dhcp.setOptions(ImmutableList.of(dhcpOption, relayInfoOption, endOption));
877 dhcp.setGatewayIPAddress(clientGwAddr.toInt());
878 }
879 dhcp.setHardwareType(DHCP.HWTYPE_ETHERNET);
880 dhcp.setHardwareAddressLength((byte) 6);
881 dhcp.setClientHardwareAddress(clientMac.toBytes());
882 dhcp.setYourIPAddress(IP_FOR_CLIENT.toInt());
883
884 UDP udp = new UDP();
885 udp.setPayload(dhcp);
886 udp.setSourcePort(UDP.DHCP_SERVER_PORT);
887 udp.setDestinationPort(UDP.DHCP_CLIENT_PORT);
888 IPv4 ipv4 = new IPv4();
889 ipv4.setPayload(udp);
890 ipv4.setDestinationAddress(IP_FOR_CLIENT.toString());
891 ipv4.setSourceAddress(SERVER_IP.toString());
892 Ethernet eth = new Ethernet();
893 if (withNonOnosRelayInfo) {
894 eth.setEtherType(Ethernet.TYPE_IPV4)
895 .setVlanID(SERVER_VLAN.toShort())
896 .setSourceMACAddress(SERVER_MAC)
897 .setDestinationMACAddress(OUTER_RELAY_MAC)
898 .setPayload(ipv4);
899 } else {
900 eth.setEtherType(Ethernet.TYPE_IPV4)
901 .setVlanID(SERVER_VLAN.toShort())
902 .setSourceMACAddress(SERVER_MAC)
903 .setDestinationMACAddress(CLIENT_MAC)
904 .setPayload(ipv4);
905 }
906
907 this.inPacket = new DefaultInboundPacket(SERVER_CONNECT_POINT, eth,
908 ByteBuffer.wrap(eth.serialize()));
909
910 }
911
912 @Override
913 public InboundPacket inPacket() {
914 return this.inPacket;
915 }
916 }
917
918 private class TestArpRequestPacketContext extends PacketContextAdapter {
919 private InboundPacket inPacket;
920
921 public TestArpRequestPacketContext(Interface fromInterface) {
922 super(0, null, null, false);
923 ARP arp = new ARP();
924 arp.setOpCode(ARP.OP_REQUEST);
925
926 IpAddress targetIp = fromInterface.ipAddressesList().get(0).ipAddress();
927 arp.setTargetProtocolAddress(targetIp.toOctets());
928 arp.setTargetHardwareAddress(MacAddress.BROADCAST.toBytes());
929 arp.setSenderHardwareAddress(MacAddress.NONE.toBytes());
930 arp.setSenderProtocolAddress(Ip4Address.valueOf(0).toOctets());
931 arp.setHardwareAddressLength((byte) MacAddress.MAC_ADDRESS_LENGTH);
932 Ethernet eth = new Ethernet();
933 eth.setEtherType(Ethernet.TYPE_ARP);
934 eth.setSourceMACAddress(MacAddress.NONE);
935 eth.setDestinationMACAddress(MacAddress.BROADCAST);
936 eth.setVlanID(fromInterface.vlan().toShort());
937 eth.setPayload(arp);
938
939 this.inPacket = new DefaultInboundPacket(fromInterface.connectPoint(), eth,
940 ByteBuffer.wrap(eth.serialize()));
941 }
942
943 @Override
944 public InboundPacket inPacket() {
945 return this.inPacket;
946 }
947 }
Kalhee Kim1b5094f2017-09-05 19:05:06 +0000948
949 /**
950 * Generates DHCP6 REQUEST packet.
951 */
952 private void buildDhcp6Packet(DHCP6 dhcp6, byte msgType, Ip6Address ip6Addr, IpPrefix prefix) {
953
954 // build address option
955 Dhcp6IaAddressOption iaAddressOption = new Dhcp6IaAddressOption();
956 iaAddressOption.setCode(DHCP6.OptionCode.IAADDR.value());
957 iaAddressOption.setIp6Address(ip6Addr);
958 iaAddressOption.setPreferredLifetime(3600);
959 iaAddressOption.setValidLifetime(1200);
960 iaAddressOption.setLength((short) Dhcp6IaAddressOption.DEFAULT_LEN);
961
962 Dhcp6IaNaOption iaNaOption = new Dhcp6IaNaOption();
963 iaNaOption.setCode(DHCP6.OptionCode.IA_NA.value());
964 iaNaOption.setIaId(0);
965 iaNaOption.setT1(302400);
966 iaNaOption.setT2(483840);
967 List<Dhcp6Option> iaNaSubOptions = new ArrayList<Dhcp6Option>();
968 iaNaSubOptions.add(iaAddressOption);
969 iaNaOption.setOptions(iaNaSubOptions);
970 iaNaOption.setLength((short) (Dhcp6IaNaOption.DEFAULT_LEN + iaAddressOption.getLength()));
971
972 // build prefix option
973 Dhcp6IaPrefixOption iaPrefixOption = new Dhcp6IaPrefixOption();
974 iaPrefixOption.setCode(DHCP6.OptionCode.IAPREFIX.value());
975 iaPrefixOption.setIp6Prefix(prefix.address().getIp6Address());
976 iaPrefixOption.setPrefixLength((byte) prefix.prefixLength());
977 iaPrefixOption.setPreferredLifetime(3601);
978 iaPrefixOption.setValidLifetime(1201);
979 iaPrefixOption.setLength((short) Dhcp6IaPrefixOption.DEFAULT_LEN);
980
981 Dhcp6IaPdOption iaPdOption = new Dhcp6IaPdOption();
982 iaPdOption.setCode(DHCP6.OptionCode.IA_PD.value());
983 iaPdOption.setIaId(0);
984 iaPdOption.setT1(302401);
985 iaPdOption.setT2(483841);
986 List<Dhcp6Option> iaPdSubOptions = new ArrayList<Dhcp6Option>();
987 iaPdSubOptions.add(iaPrefixOption);
988 iaPdOption.setOptions(iaPdSubOptions);
989 iaPdOption.setLength((short) (Dhcp6IaPdOption.DEFAULT_LEN + iaPrefixOption.getLength()));
990
991 dhcp6.setMsgType(msgType);
992 List<Dhcp6Option> dhcp6Options = new ArrayList<Dhcp6Option>();
993 dhcp6Options.add(iaNaOption);
994 dhcp6Options.add(iaPdOption);
995 dhcp6.setOptions(dhcp6Options);
996
997 }
998
999 private void buildRelayMsg(DHCP6 dhcp6Relay, byte msgType, Ip6Address linkAddr,
1000 Ip6Address peerAddr, byte hop, byte[] interfaceIdBytes,
1001 DHCP6 dhcp6Payload) {
1002
1003 dhcp6Relay.setMsgType(msgType);
1004
1005 dhcp6Relay.setLinkAddress(linkAddr.toOctets());
1006 dhcp6Relay.setPeerAddress(peerAddr.toOctets());
1007 dhcp6Relay.setHopCount(hop);
1008 List<Dhcp6Option> options = new ArrayList<Dhcp6Option>();
1009
1010 // interfaceId option
1011 Dhcp6Option interfaceId = new Dhcp6Option();
1012 interfaceId.setCode(DHCP6.OptionCode.INTERFACE_ID.value());
1013
1014
1015 interfaceId.setData(interfaceIdBytes);
1016 interfaceId.setLength((short) interfaceIdBytes.length);
1017 Dhcp6InterfaceIdOption interfaceIdOption = new Dhcp6InterfaceIdOption(interfaceId);
1018 ByteBuffer bb = ByteBuffer.wrap(interfaceIdBytes);
1019
1020 byte[] macAddr = new byte[MacAddress.MAC_ADDRESS_LENGTH];
1021 byte[] port = new byte[21];
1022 bb.get(macAddr);
1023 bb.get(); // separator
1024 bb.get(port);
1025 interfaceIdOption.setMacAddress(MacAddress.valueOf(macAddr));
1026 interfaceIdOption.setInPort(port);
1027
1028 options.add(interfaceIdOption);
1029
1030 // relay message option
1031 Dhcp6Option relayMsgOption = new Dhcp6Option();
1032 relayMsgOption.setCode(DHCP6.OptionCode.RELAY_MSG.value());
1033 byte[] dhcp6PayloadByte = dhcp6Payload.serialize();
1034 relayMsgOption.setLength((short) dhcp6PayloadByte.length);
1035 relayMsgOption.setPayload(dhcp6Payload);
1036 Dhcp6RelayOption relayOpt = new Dhcp6RelayOption(relayMsgOption);
1037
1038 options.add(relayOpt);
1039
1040 dhcp6Relay.setOptions(options);
1041 }
1042 private byte[] buildInterfaceId(MacAddress clientMac, ConnectPoint clientCp) {
1043 String inPortString = "-" + clientCp.toString();
1044 byte[] clientSoureMacBytes = clientMac.toBytes();
1045 byte[] inPortStringBytes = inPortString.getBytes();
1046 byte[] interfaceIdBytes = new byte[clientSoureMacBytes.length + inPortStringBytes.length];
1047
1048 System.arraycopy(clientSoureMacBytes, 0, interfaceIdBytes, 0, clientSoureMacBytes.length);
1049 System.arraycopy(inPortStringBytes, 0, interfaceIdBytes, clientSoureMacBytes.length, inPortStringBytes.length);
1050
1051 return interfaceIdBytes;
1052 }
1053
1054 private class TestDhcp6RequestPacketContext extends PacketContextAdapter {
1055
1056
1057 private InboundPacket inPacket;
1058
1059
1060 public TestDhcp6RequestPacketContext(MacAddress clientMac, VlanId vlanId,
1061 ConnectPoint clientCp,
1062 Ip6Address clientGwAddr,
1063 int relayLevel) {
1064 super(0, null, null, false);
1065
1066 DHCP6 dhcp6 = new DHCP6();
1067 if (relayLevel > 0) {
1068 DHCP6 dhcp6Payload = new DHCP6();
1069 buildDhcp6Packet(dhcp6Payload, DHCP6.MsgType.REQUEST.value(),
1070 IP_FOR_CLIENT_V6,
1071 PREFIX_FOR_ZERO);
1072 DHCP6 dhcp6Parent = null;
1073 DHCP6 dhcp6Child = dhcp6Payload;
1074 for (int i = 0; i < relayLevel; i++) {
1075 dhcp6Parent = new DHCP6();
1076 byte[] interfaceId = buildInterfaceId(clientMac, clientCp);
1077 buildRelayMsg(dhcp6Parent, DHCP6.MsgType.RELAY_FORW.value(),
1078 INTERFACE_IP_V6.ipAddress().getIp6Address(),
1079 OUTER_RELAY_IP_V6,
1080 (byte) (relayLevel - 1), interfaceId,
1081 dhcp6Child);
1082 dhcp6Child = dhcp6Parent;
1083 }
1084 if (dhcp6Parent != null) {
1085 dhcp6 = dhcp6Parent;
1086 }
1087 } else {
1088 buildDhcp6Packet(dhcp6, DHCP6.MsgType.REQUEST.value(),
1089 IP_FOR_CLIENT_V6,
1090 PREFIX_FOR_ZERO);
1091 }
1092
1093 UDP udp = new UDP();
1094 udp.setPayload(dhcp6);
1095 if (relayLevel > 0) {
1096 udp.setSourcePort(UDP.DHCP_V6_SERVER_PORT);
1097 } else {
1098 udp.setSourcePort(UDP.DHCP_V6_CLIENT_PORT);
1099 }
1100 udp.setDestinationPort(UDP.DHCP_V6_SERVER_PORT);
1101
1102 IPv6 ipv6 = new IPv6();
1103 ipv6.setPayload(udp);
1104 ipv6.setNextHeader(IPv6.PROTOCOL_UDP);
1105 ipv6.setDestinationAddress(SERVER_IP_V6_MCAST.toOctets());
1106 ipv6.setSourceAddress(clientGwAddr.toOctets());
1107
1108 Ethernet eth = new Ethernet();
1109 if (relayLevel > 0) {
1110 eth.setEtherType(Ethernet.TYPE_IPV6)
1111 .setVlanID(vlanId.toShort())
1112 .setSourceMACAddress(OUTER_RELAY_MAC)
1113 .setDestinationMACAddress(MacAddress.valueOf("33:33:00:01:00:02"))
1114 .setPayload(ipv6);
1115 } else {
1116 eth.setEtherType(Ethernet.TYPE_IPV6)
1117 .setVlanID(vlanId.toShort())
1118 .setSourceMACAddress(clientMac)
1119 .setDestinationMACAddress(MacAddress.valueOf("33:33:00:01:00:02"))
1120 .setPayload(ipv6);
1121 }
1122 this.inPacket = new DefaultInboundPacket(clientCp, eth,
1123 ByteBuffer.wrap(eth.serialize()));
1124 }
1125
1126 @Override
1127 public InboundPacket inPacket() {
1128 return this.inPacket;
1129 }
1130 }
1131
1132 /**
1133 * Generates DHCP6 REPLY packet.
1134 */
1135
1136 private class TestDhcp6ReplyPacketContext extends PacketContextAdapter {
1137 private InboundPacket inPacket;
1138
1139 public TestDhcp6ReplyPacketContext(ConnectPoint clientCp, MacAddress clientMac,
1140 VlanId clientVlan, Ip6Address clientGwAddr,
1141 int relayLevel) {
1142 super(0, null, null, false);
1143
1144
1145 DHCP6 dhcp6Payload = new DHCP6();
1146 buildDhcp6Packet(dhcp6Payload, DHCP6.MsgType.REPLY.value(),
1147 IP_FOR_CLIENT_V6,
1148 PREFIX_FOR_CLIENT_V6);
1149 byte[] interfaceId = buildInterfaceId(clientMac, clientCp);
1150 DHCP6 dhcp6 = new DHCP6();
1151 buildRelayMsg(dhcp6, DHCP6.MsgType.RELAY_REPL.value(),
1152 INTERFACE_IP_V6.ipAddress().getIp6Address(),
1153 OUTER_RELAY_IP_V6,
1154 (byte) 0, interfaceId,
1155 dhcp6Payload);
1156
1157 DHCP6 dhcp6Parent = null;
1158 DHCP6 dhcp6Child = dhcp6;
1159 for (int i = 0; i < relayLevel; i++) { // relayLevel 0 : no relay
1160 dhcp6Parent = new DHCP6();
1161
1162 buildRelayMsg(dhcp6Parent, DHCP6.MsgType.RELAY_REPL.value(),
1163 INTERFACE_IP_V6.ipAddress().getIp6Address(),
1164 OUTER_RELAY_IP_V6,
1165 (byte) relayLevel, interfaceId,
1166 dhcp6Child);
1167
1168 dhcp6Child = dhcp6Parent;
1169 }
1170 if (dhcp6Parent != null) {
1171 dhcp6 = dhcp6Parent;
1172 }
1173
1174
1175 UDP udp = new UDP();
1176 udp.setPayload(dhcp6);
1177 udp.setSourcePort(UDP.DHCP_V6_SERVER_PORT);
1178 udp.setDestinationPort(UDP.DHCP_V6_CLIENT_PORT);
1179 IPv6 ipv6 = new IPv6();
1180 ipv6.setPayload(udp);
1181 ipv6.setNextHeader(IPv6.PROTOCOL_UDP);
1182 ipv6.setDestinationAddress(IP_FOR_CLIENT_V6.toOctets());
1183 ipv6.setSourceAddress(SERVER_IP_V6.toOctets());
1184 Ethernet eth = new Ethernet();
1185 if (relayLevel > 0) {
1186 eth.setEtherType(Ethernet.TYPE_IPV6)
1187 .setVlanID(SERVER_VLAN.toShort())
1188 .setSourceMACAddress(SERVER_MAC)
1189 .setDestinationMACAddress(OUTER_RELAY_MAC)
1190 .setPayload(ipv6);
1191 } else {
1192 eth.setEtherType(Ethernet.TYPE_IPV6)
1193 .setVlanID(SERVER_VLAN.toShort())
1194 .setSourceMACAddress(SERVER_MAC)
1195 .setDestinationMACAddress(CLIENT_MAC)
1196 .setPayload(ipv6);
1197 }
1198
1199 this.inPacket = new DefaultInboundPacket(SERVER_CONNECT_POINT, eth,
1200 ByteBuffer.wrap(eth.serialize()));
1201
1202 }
1203
1204 @Override
1205 public InboundPacket inPacket() {
1206 return this.inPacket;
1207 }
1208 }
1209
Yi Tseng7a38f9a2017-06-09 14:36:40 -07001210}