blob: 8b52c34d985562129ca6a5488ad9add44192ce75 [file] [log] [blame]
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
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.cordvtn;
17
Hyunsun Moonc71231d2015-12-16 20:53:23 -080018import com.google.common.collect.Lists;
19import com.google.common.collect.Maps;
20import org.onlab.packet.Ethernet;
Hyunsun Moon4a915152016-01-14 16:56:26 -080021import org.onlab.packet.IPv4;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080022import org.onlab.packet.Ip4Address;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080023import org.onlab.packet.Ip4Prefix;
24import org.onlab.packet.IpAddress;
25import org.onlab.packet.IpPrefix;
26import org.onlab.packet.MacAddress;
Hyunsun Moon4a915152016-01-14 16:56:26 -080027import org.onlab.packet.TpPort;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080028import org.onlab.util.ItemNotFoundException;
29import org.onosproject.core.ApplicationId;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080030import org.onosproject.core.DefaultGroupId;
31import org.onosproject.core.GroupId;
32import org.onosproject.mastership.MastershipService;
33import org.onosproject.net.Device;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080034import org.onosproject.net.DeviceId;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080035import org.onosproject.net.Host;
Hyunsun Moon5a4346f2016-01-15 11:41:14 -080036import org.onosproject.net.Port;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080037import org.onosproject.net.PortNumber;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080038import org.onosproject.net.behaviour.ExtensionTreatmentResolver;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080039import org.onosproject.net.device.DeviceService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080040import org.onosproject.net.driver.DefaultDriverData;
41import org.onosproject.net.driver.DefaultDriverHandler;
42import org.onosproject.net.driver.Driver;
43import org.onosproject.net.driver.DriverHandler;
44import org.onosproject.net.driver.DriverService;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080045import org.onosproject.net.flow.DefaultFlowRule;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080046import org.onosproject.net.flow.DefaultTrafficSelector;
47import org.onosproject.net.flow.DefaultTrafficTreatment;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080048import org.onosproject.net.flow.FlowRule;
49import org.onosproject.net.flow.FlowRuleOperations;
50import org.onosproject.net.flow.FlowRuleOperationsContext;
51import org.onosproject.net.flow.FlowRuleService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080052import org.onosproject.net.flow.TrafficSelector;
53import org.onosproject.net.flow.TrafficTreatment;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080054import org.onosproject.net.flow.criteria.Criterion;
55import org.onosproject.net.flow.criteria.EthCriterion;
56import org.onosproject.net.flow.criteria.IPCriterion;
57import org.onosproject.net.flow.criteria.PortCriterion;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080058import org.onosproject.net.flow.instructions.ExtensionPropertyException;
59import org.onosproject.net.flow.instructions.ExtensionTreatment;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080060import org.onosproject.net.flow.instructions.Instruction;
61import org.onosproject.net.flow.instructions.Instructions;
62import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
63import org.onosproject.net.group.DefaultGroupBucket;
64import org.onosproject.net.group.DefaultGroupDescription;
65import org.onosproject.net.group.DefaultGroupKey;
66import org.onosproject.net.group.Group;
67import org.onosproject.net.group.GroupBucket;
68import org.onosproject.net.group.GroupBuckets;
69import org.onosproject.net.group.GroupDescription;
70import org.onosproject.net.group.GroupKey;
71import org.onosproject.net.group.GroupService;
72import org.onosproject.openstackswitching.OpenstackNetwork;
73import org.onosproject.openstackswitching.OpenstackSubnet;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080074import org.slf4j.Logger;
75
Hyunsun Moon4161e6f2016-01-07 01:32:31 -080076import java.util.ArrayList;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080077import java.util.List;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080078import java.util.Map;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080079import java.util.Objects;
80import java.util.Set;
81import java.util.stream.Collectors;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080082
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080083import static com.google.common.base.Preconditions.checkNotNull;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080084import static org.onosproject.net.Device.Type.SWITCH;
85import static org.onosproject.net.flow.criteria.Criterion.Type.IN_PORT;
86import static org.onosproject.net.flow.criteria.Criterion.Type.IPV4_DST;
87import static org.onosproject.net.flow.criteria.Criterion.Type.IPV4_SRC;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080088import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080089import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.ETH_DST;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080090import static org.slf4j.LoggerFactory.getLogger;
91
92/**
Hyunsun Moonc71231d2015-12-16 20:53:23 -080093 * Populates rules for CORD VTN service.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080094 */
Hyunsun Moonc71231d2015-12-16 20:53:23 -080095public class CordVtnRuleInstaller {
96
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080097 protected final Logger log = getLogger(getClass());
98
Hyunsun Moon133fd792016-02-09 01:55:48 -080099 private static final String PORT_NAME = "portName";
Hyunsun Moon4a915152016-01-14 16:56:26 -0800100 private static final int TABLE_FIRST = 0;
101 private static final int TABLE_IN_PORT = 1;
102 private static final int TABLE_ACCESS_TYPE = 2;
103 private static final int TABLE_IN_SERVICE = 3;
104 private static final int TABLE_DST_IP = 4;
105 private static final int TABLE_TUNNEL_IN = 5;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800106
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800107 private static final int MANAGEMENT_PRIORITY = 55000;
108 private static final int HIGH_PRIORITY = 50000;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800109 private static final int DEFAULT_PRIORITY = 5000;
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800110 private static final int LOW_PRIORITY = 4000;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800111 private static final int LOWEST_PRIORITY = 0;
Hyunsun Moon4a915152016-01-14 16:56:26 -0800112
113 private static final int VXLAN_UDP_PORT = 4789;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800114
115 private final ApplicationId appId;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800116 private final FlowRuleService flowRuleService;
117 private final DeviceService deviceService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800118 private final DriverService driverService;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800119 private final GroupService groupService;
120 private final MastershipService mastershipService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800121 private final String tunnelType;
122
123 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800124 * Creates a new rule populator.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800125 *
126 * @param appId application id
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800127 * @param flowRuleService flow rule service
128 * @param deviceService device service
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800129 * @param driverService driver service
Jian Lidfba7392016-01-22 16:46:58 -0800130 * @param groupService group service
131 * @param mastershipService mastership service
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800132 * @param tunnelType tunnel type
133 */
134 public CordVtnRuleInstaller(ApplicationId appId,
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800135 FlowRuleService flowRuleService,
136 DeviceService deviceService,
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800137 DriverService driverService,
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800138 GroupService groupService,
139 MastershipService mastershipService,
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800140 String tunnelType) {
141 this.appId = appId;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800142 this.flowRuleService = flowRuleService;
143 this.deviceService = deviceService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800144 this.driverService = driverService;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800145 this.groupService = groupService;
146 this.mastershipService = mastershipService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800147 this.tunnelType = checkNotNull(tunnelType);
148 }
149
150 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800151 * Installs table miss rule to a give device.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800152 *
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800153 * @param deviceId device id to install the rules
Hyunsun Moon133fd792016-02-09 01:55:48 -0800154 * @param dpIntf data plane interface name
155 * @param dpIp data plane ip address
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800156 */
Hyunsun Moon133fd792016-02-09 01:55:48 -0800157 public void init(DeviceId deviceId, String dpIntf, IpAddress dpIp) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800158 // default is drop packets which can be accomplished without
159 // a table miss entry for all table.
Hyunsun Moon4a915152016-01-14 16:56:26 -0800160 PortNumber tunnelPort = getTunnelPort(deviceId);
Hyunsun Moon133fd792016-02-09 01:55:48 -0800161 PortNumber dpPort = getDpPort(deviceId, dpIntf);
Hyunsun Moon4a915152016-01-14 16:56:26 -0800162
Hyunsun Moon133fd792016-02-09 01:55:48 -0800163 processFirstTable(deviceId, dpPort, dpIp);
164 processInPortTable(deviceId, tunnelPort, dpPort);
165 processAccessTypeTable(deviceId, dpPort);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800166 }
167
168 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800169 * Populates basic rules that connect a VM to the other VMs in the system.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800170 *
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800171 * @param host host
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800172 * @param tunnelIp tunnel ip
173 * @param vNet openstack network
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800174 */
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800175 public void populateBasicConnectionRules(Host host, IpAddress tunnelIp, OpenstackNetwork vNet) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800176 checkNotNull(host);
177 checkNotNull(vNet);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800178
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800179 DeviceId deviceId = host.location().deviceId();
180 if (!mastershipService.isLocalMaster(deviceId)) {
181 return;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800182 }
183
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800184 PortNumber inPort = host.location().port();
185 MacAddress dstMac = host.mac();
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800186 IpAddress hostIp = host.ipAddresses().stream().findFirst().get();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800187 long tunnelId = Long.parseLong(vNet.segmentId());
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800188
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800189 OpenstackSubnet subnet = vNet.subnets().stream()
190 .findFirst()
191 .orElse(null);
192
193 if (subnet == null) {
194 log.error("Failed to get subnet for {}", host.id());
195 return;
196 }
197
198 populateLocalInPortRule(deviceId, inPort, hostIp);
199 populateDirectAccessRule(Ip4Prefix.valueOf(subnet.cidr()), Ip4Prefix.valueOf(subnet.cidr()));
Hyunsun Moon81ab23b2016-02-01 23:00:56 -0800200 populateServiceIsolationRule(Ip4Prefix.valueOf(subnet.cidr()));
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800201 populateDstIpRule(deviceId, inPort, dstMac, hostIp, tunnelId, tunnelIp);
202 populateTunnelInRule(deviceId, inPort, dstMac, tunnelId);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800203 }
204
205 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800206 * Removes basic rules related to a given flow information.
207 *
208 * @param host host to be removed
209 */
210 public void removeBasicConnectionRules(Host host) {
211 checkNotNull(host);
212
213 DeviceId deviceId = host.location().deviceId();
214 MacAddress mac = host.mac();
215 PortNumber port = host.location().port();
216 IpAddress ip = host.ipAddresses().stream().findFirst().orElse(null);
217
218 if (!mastershipService.isLocalMaster(deviceId)) {
219 return;
220 }
221
222 for (FlowRule flowRule : flowRuleService.getFlowRulesById(appId)) {
223 if (flowRule.deviceId().equals(deviceId)) {
224 PortNumber inPort = getInPort(flowRule);
225 if (inPort != null && inPort.equals(port)) {
226 processFlowRule(false, flowRule);
227 continue;
228 }
229 }
230
231 MacAddress dstMac = getDstMacFromTreatment(flowRule);
232 if (dstMac != null && dstMac.equals(mac)) {
233 processFlowRule(false, flowRule);
234 continue;
235 }
236
237 dstMac = getDstMacFromSelector(flowRule);
238 if (dstMac != null && dstMac.equals(mac)) {
239 processFlowRule(false, flowRule);
240 continue;
241 }
242
243 IpPrefix dstIp = getDstIpFromSelector(flowRule);
244 if (dstIp != null && dstIp.equals(ip.toIpPrefix())) {
245 processFlowRule(false, flowRule);
246 }
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800247 }
248
249 // TODO uninstall same network access rule in access table if no vm exists in the network
250 }
251
252 /**
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800253 * Populates service dependency rules.
254 *
255 * @param tService tenant cord service
256 * @param pService provider cord service
257 */
258 public void populateServiceDependencyRules(CordService tService, CordService pService) {
259 checkNotNull(tService);
260 checkNotNull(pService);
261
262 Ip4Prefix srcRange = tService.serviceIpRange().getIp4Prefix();
263 Ip4Prefix dstRange = pService.serviceIpRange().getIp4Prefix();
264 Ip4Address serviceIp = pService.serviceIp().getIp4Address();
265
266 Map<DeviceId, GroupId> outGroups = Maps.newHashMap();
267 Map<DeviceId, Set<PortNumber>> inPorts = Maps.newHashMap();
268
269 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
270 GroupId groupId = createServiceGroup(device.id(), pService);
271 outGroups.put(device.id(), groupId);
272
273 Set<PortNumber> vms = tService.hosts().keySet()
274 .stream()
275 .filter(host -> host.location().deviceId().equals(device.id()))
276 .map(host -> host.location().port())
277 .collect(Collectors.toSet());
278 inPorts.put(device.id(), vms);
279 }
280
281 populateIndirectAccessRule(srcRange, serviceIp, outGroups);
282 populateDirectAccessRule(srcRange, dstRange);
283 populateInServiceRule(inPorts, outGroups);
284 }
285
286 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800287 * Removes service dependency rules.
288 *
289 * @param tService tenant cord service
290 * @param pService provider cord service
291 */
292 public void removeServiceDependencyRules(CordService tService, CordService pService) {
293 checkNotNull(tService);
294 checkNotNull(pService);
295
296 Ip4Prefix srcRange = tService.serviceIpRange().getIp4Prefix();
297 Ip4Prefix dstRange = pService.serviceIpRange().getIp4Prefix();
298 IpPrefix serviceIp = pService.serviceIp().toIpPrefix();
299
300 Map<DeviceId, GroupId> outGroups = Maps.newHashMap();
301 GroupKey groupKey = new DefaultGroupKey(pService.id().id().getBytes());
302
303 deviceService.getAvailableDevices(SWITCH).forEach(device -> {
304 Group group = groupService.getGroup(device.id(), groupKey);
305 if (group != null) {
306 outGroups.put(device.id(), group.id());
307 }
308 });
309
310 for (FlowRule flowRule : flowRuleService.getFlowRulesById(appId)) {
311 IpPrefix dstIp = getDstIpFromSelector(flowRule);
312 IpPrefix srcIp = getSrcIpFromSelector(flowRule);
313
314 if (dstIp != null && dstIp.equals(serviceIp)) {
315 processFlowRule(false, flowRule);
316 continue;
317 }
318
319 if (dstIp != null && srcIp != null) {
320 if (dstIp.equals(dstRange) && srcIp.equals(srcRange)) {
321 processFlowRule(false, flowRule);
322 continue;
323 }
324
325 if (dstIp.equals(srcRange) && srcIp.equals(dstRange)) {
326 processFlowRule(false, flowRule);
327 continue;
328 }
329 }
330
331 GroupId groupId = getGroupIdFromTreatment(flowRule);
332 if (groupId != null && groupId.equals(outGroups.get(flowRule.deviceId()))) {
333 processFlowRule(false, flowRule);
334 }
335 }
336
337 // TODO remove the group if it is not in use
338 }
339
340 /**
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800341 * Updates group buckets for a given service to all devices.
342 *
343 * @param service cord service
344 */
345 public void updateServiceGroup(CordService service) {
346 checkNotNull(service);
347
348 GroupKey groupKey = getGroupKey(service.id());
349
350 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
351 DeviceId deviceId = device.id();
352 if (!mastershipService.isLocalMaster(deviceId)) {
353 continue;
354 }
355
356 Group group = groupService.getGroup(deviceId, groupKey);
357 if (group == null) {
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800358 log.trace("No group exists for service {} in {}, do nothing.", service.id(), deviceId);
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800359 continue;
360 }
361
362 List<GroupBucket> oldBuckets = group.buckets().buckets();
363 List<GroupBucket> newBuckets = getServiceGroupBuckets(
364 deviceId, service.segmentationId(), service.hosts()).buckets();
365
366 if (oldBuckets.equals(newBuckets)) {
367 continue;
368 }
369
370 List<GroupBucket> bucketsToRemove = new ArrayList<>(oldBuckets);
371 bucketsToRemove.removeAll(newBuckets);
372 if (!bucketsToRemove.isEmpty()) {
373 groupService.removeBucketsFromGroup(
374 deviceId,
375 groupKey,
376 new GroupBuckets(bucketsToRemove),
377 groupKey, appId);
378 }
379
380 List<GroupBucket> bucketsToAdd = new ArrayList<>(newBuckets);
381 bucketsToAdd.removeAll(oldBuckets);
382 if (!bucketsToAdd.isEmpty()) {
383 groupService.addBucketsToGroup(
384 deviceId,
385 groupKey,
386 new GroupBuckets(bucketsToAdd),
387 groupKey, appId);
388 }
389 }
390 }
391
392 /**
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800393 * Populates flow rules for management network access.
394 *
395 * @param host host which has management network interface
396 * @param mService management network service
397 */
398 public void populateManagementNetworkRules(Host host, CordService mService) {
399 checkNotNull(mService);
400
401 DeviceId deviceId = host.location().deviceId();
402 IpAddress hostIp = host.ipAddresses().stream().findFirst().get();
403
404 TrafficSelector selector = DefaultTrafficSelector.builder()
405 .matchEthType(Ethernet.TYPE_ARP)
406 .matchArpTpa(mService.serviceIp().getIp4Address())
407 .build();
408
409 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
410 .setOutput(PortNumber.LOCAL)
411 .build();
412
413 FlowRule flowRule = DefaultFlowRule.builder()
414 .fromApp(appId)
415 .withSelector(selector)
416 .withTreatment(treatment)
417 .withPriority(MANAGEMENT_PRIORITY)
418 .forDevice(deviceId)
419 .forTable(TABLE_FIRST)
420 .makePermanent()
421 .build();
422
423 processFlowRule(true, flowRule);
424
425 selector = DefaultTrafficSelector.builder()
426 .matchInPort(PortNumber.LOCAL)
427 .matchEthType(Ethernet.TYPE_ARP)
428 .matchArpTpa(hostIp.getIp4Address())
429 .build();
430
431 treatment = DefaultTrafficTreatment.builder()
432 .setOutput(host.location().port())
433 .build();
434
435 flowRule = DefaultFlowRule.builder()
436 .fromApp(appId)
437 .withSelector(selector)
438 .withTreatment(treatment)
439 .withPriority(MANAGEMENT_PRIORITY)
440 .forDevice(deviceId)
441 .forTable(TABLE_FIRST)
442 .makePermanent()
443 .build();
444
445 processFlowRule(true, flowRule);
446
447 selector = DefaultTrafficSelector.builder()
448 .matchInPort(PortNumber.LOCAL)
449 .matchEthType(Ethernet.TYPE_IPV4)
450 .matchIPDst(mService.serviceIpRange())
451 .build();
452
453 treatment = DefaultTrafficTreatment.builder()
454 .transition(TABLE_DST_IP)
455 .build();
456
457 flowRule = DefaultFlowRule.builder()
458 .fromApp(appId)
459 .withSelector(selector)
460 .withTreatment(treatment)
461 .withPriority(MANAGEMENT_PRIORITY)
462 .forDevice(deviceId)
463 .forTable(TABLE_FIRST)
464 .makePermanent()
465 .build();
466
467 processFlowRule(true, flowRule);
468
469 selector = DefaultTrafficSelector.builder()
470 .matchEthType(Ethernet.TYPE_IPV4)
471 .matchIPDst(mService.serviceIp().toIpPrefix())
472 .build();
473
474 treatment = DefaultTrafficTreatment.builder()
475 .setOutput(PortNumber.LOCAL)
476 .build();
477
478 flowRule = DefaultFlowRule.builder()
479 .fromApp(appId)
480 .withSelector(selector)
481 .withTreatment(treatment)
482 .withPriority(MANAGEMENT_PRIORITY)
483 .forDevice(deviceId)
484 .forTable(TABLE_ACCESS_TYPE)
485 .makePermanent()
486 .build();
487
488 processFlowRule(true, flowRule);
489 }
490
491 /**
492 * Removes management network access rules.
493 *
494 * @param host host to be removed
495 * @param mService service for management network
496 */
497 public void removeManagementNetworkRules(Host host, CordService mService) {
498 checkNotNull(mService);
499
500 for (FlowRule flowRule : flowRuleService.getFlowRulesById(appId)) {
501 if (flowRule.deviceId().equals(host.location().deviceId())) {
502 PortNumber port = getOutputFromTreatment(flowRule);
503 if (port != null && port.equals(host.location().port())) {
504 processFlowRule(false, flowRule);
505 }
506 }
507
508 // TODO remove the other rules if mgmt network is not in use
509 }
510 }
511
512 /**
Hyunsun Moon4a915152016-01-14 16:56:26 -0800513 * Populates default rules on the first table.
Hyunsun Moon133fd792016-02-09 01:55:48 -0800514 * It includes the rules for shuttling vxlan-encapped packets between ovs and
515 * linux stack,and external network connectivity.
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800516 *
517 * @param deviceId device id
Hyunsun Moon133fd792016-02-09 01:55:48 -0800518 * @param dpPort data plane interface port number
519 * @param dpIp data plane ip address
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800520 */
Hyunsun Moon133fd792016-02-09 01:55:48 -0800521 private void processFirstTable(DeviceId deviceId, PortNumber dpPort, IpAddress dpIp) {
Hyunsun Moon4a915152016-01-14 16:56:26 -0800522 // take vxlan packet out onto the physical port
523 TrafficSelector selector = DefaultTrafficSelector.builder()
524 .matchInPort(PortNumber.LOCAL)
525 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800526
Hyunsun Moon4a915152016-01-14 16:56:26 -0800527 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Hyunsun Moon133fd792016-02-09 01:55:48 -0800528 .setOutput(dpPort)
Hyunsun Moon4a915152016-01-14 16:56:26 -0800529 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800530
Hyunsun Moon4a915152016-01-14 16:56:26 -0800531 FlowRule flowRule = DefaultFlowRule.builder()
532 .fromApp(appId)
533 .withSelector(selector)
534 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800535 .withPriority(HIGH_PRIORITY)
Hyunsun Moon4a915152016-01-14 16:56:26 -0800536 .forDevice(deviceId)
537 .forTable(TABLE_FIRST)
538 .makePermanent()
539 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800540
Hyunsun Moon4a915152016-01-14 16:56:26 -0800541 processFlowRule(true, flowRule);
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800542
Hyunsun Moon4a915152016-01-14 16:56:26 -0800543 // take a vxlan encap'd packet through the Linux stack
544 selector = DefaultTrafficSelector.builder()
Hyunsun Moon133fd792016-02-09 01:55:48 -0800545 .matchInPort(dpPort)
Hyunsun Moon4a915152016-01-14 16:56:26 -0800546 .matchEthType(Ethernet.TYPE_IPV4)
547 .matchIPProtocol(IPv4.PROTOCOL_UDP)
548 .matchUdpDst(TpPort.tpPort(VXLAN_UDP_PORT))
549 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800550
Hyunsun Moon4a915152016-01-14 16:56:26 -0800551 treatment = DefaultTrafficTreatment.builder()
552 .setOutput(PortNumber.LOCAL)
553 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800554
Hyunsun Moon4a915152016-01-14 16:56:26 -0800555 flowRule = DefaultFlowRule.builder()
556 .fromApp(appId)
557 .withSelector(selector)
558 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800559 .withPriority(HIGH_PRIORITY)
Hyunsun Moon4a915152016-01-14 16:56:26 -0800560 .forDevice(deviceId)
561 .forTable(TABLE_FIRST)
562 .makePermanent()
563 .build();
564
565 processFlowRule(true, flowRule);
566
Hyunsun Moon133fd792016-02-09 01:55:48 -0800567 // take a packet to the data plane ip through Linux stack
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800568 selector = DefaultTrafficSelector.builder()
Hyunsun Moon133fd792016-02-09 01:55:48 -0800569 .matchInPort(dpPort)
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800570 .matchEthType(Ethernet.TYPE_IPV4)
Hyunsun Moon133fd792016-02-09 01:55:48 -0800571 .matchIPDst(dpIp.toIpPrefix())
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800572 .build();
573
574 treatment = DefaultTrafficTreatment.builder()
575 .setOutput(PortNumber.LOCAL)
576 .build();
577
578 flowRule = DefaultFlowRule.builder()
579 .fromApp(appId)
580 .withSelector(selector)
581 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800582 .withPriority(HIGH_PRIORITY)
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800583 .forDevice(deviceId)
584 .forTable(TABLE_FIRST)
585 .makePermanent()
586 .build();
587
588 processFlowRule(true, flowRule);
589
590 // take an arp packet from physical through Linux stack
591 selector = DefaultTrafficSelector.builder()
Hyunsun Moon133fd792016-02-09 01:55:48 -0800592 .matchInPort(dpPort)
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800593 .matchEthType(Ethernet.TYPE_ARP)
594 .build();
595
596 treatment = DefaultTrafficTreatment.builder()
597 .setOutput(PortNumber.LOCAL)
598 .build();
599
600 flowRule = DefaultFlowRule.builder()
601 .fromApp(appId)
602 .withSelector(selector)
603 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800604 .withPriority(HIGH_PRIORITY)
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800605 .forDevice(deviceId)
606 .forTable(TABLE_FIRST)
607 .makePermanent()
608 .build();
609
610 processFlowRule(true, flowRule);
611
Hyunsun Moon4a915152016-01-14 16:56:26 -0800612 // take all else to the next table
613 selector = DefaultTrafficSelector.builder()
614 .build();
615
616 treatment = DefaultTrafficTreatment.builder()
617 .transition(TABLE_IN_PORT)
618 .build();
619
620 flowRule = DefaultFlowRule.builder()
621 .fromApp(appId)
622 .withSelector(selector)
623 .withTreatment(treatment)
624 .withPriority(LOWEST_PRIORITY)
625 .forDevice(deviceId)
626 .forTable(TABLE_FIRST)
627 .makePermanent()
628 .build();
629
630 processFlowRule(true, flowRule);
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800631 }
632
633 /**
Hyunsun Moon133fd792016-02-09 01:55:48 -0800634 * Forward table miss packets in ACCESS_TYPE table to data plane port.
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800635 *
636 * @param deviceId device id
Hyunsun Moon133fd792016-02-09 01:55:48 -0800637 * @param dpPort data plane interface port number
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800638 */
Hyunsun Moon133fd792016-02-09 01:55:48 -0800639 private void processAccessTypeTable(DeviceId deviceId, PortNumber dpPort) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800640 TrafficSelector selector = DefaultTrafficSelector.builder()
641 .build();
642
643 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Hyunsun Moon133fd792016-02-09 01:55:48 -0800644 .setOutput(dpPort)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800645 .build();
646
647 FlowRule flowRule = DefaultFlowRule.builder()
648 .fromApp(appId)
649 .withSelector(selector)
650 .withTreatment(treatment)
651 .withPriority(LOWEST_PRIORITY)
652 .forDevice(deviceId)
653 .forTable(TABLE_ACCESS_TYPE)
654 .makePermanent()
655 .build();
656
657 processFlowRule(true, flowRule);
658 }
659
660 /**
Hyunsun Moon4a915152016-01-14 16:56:26 -0800661 * Populates default rules for IN_PORT table.
662 * All packets from tunnel port are forwarded to TUNNEL_ID table and all packets
Hyunsun Moon133fd792016-02-09 01:55:48 -0800663 * from data plane interface port to ACCESS_TYPE table.
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800664 *
665 * @param deviceId device id to install the rules
Hyunsun Moon4a915152016-01-14 16:56:26 -0800666 * @param tunnelPort tunnel port number
Hyunsun Moon133fd792016-02-09 01:55:48 -0800667 * @param dpPort data plane interface port number
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800668 */
Hyunsun Moon133fd792016-02-09 01:55:48 -0800669 private void processInPortTable(DeviceId deviceId, PortNumber tunnelPort, PortNumber dpPort) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800670 checkNotNull(tunnelPort);
671
672 TrafficSelector selector = DefaultTrafficSelector.builder()
673 .matchInPort(tunnelPort)
674 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800675
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800676 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
677 .transition(TABLE_TUNNEL_IN)
678 .build();
679
680 FlowRule flowRule = DefaultFlowRule.builder()
681 .fromApp(appId)
682 .withSelector(selector)
683 .withTreatment(treatment)
684 .withPriority(DEFAULT_PRIORITY)
685 .forDevice(deviceId)
686 .forTable(TABLE_IN_PORT)
687 .makePermanent()
688 .build();
689
690 processFlowRule(true, flowRule);
Hyunsun Moon4a915152016-01-14 16:56:26 -0800691
692 selector = DefaultTrafficSelector.builder()
Hyunsun Moon133fd792016-02-09 01:55:48 -0800693 .matchInPort(dpPort)
Hyunsun Moon4a915152016-01-14 16:56:26 -0800694 .build();
695
696 treatment = DefaultTrafficTreatment.builder()
697 .transition(TABLE_DST_IP)
698 .build();
699
700 flowRule = DefaultFlowRule.builder()
701 .fromApp(appId)
702 .withSelector(selector)
703 .withTreatment(treatment)
704 .withPriority(DEFAULT_PRIORITY)
705 .forDevice(deviceId)
706 .forTable(TABLE_IN_PORT)
707 .makePermanent()
708 .build();
709
710 processFlowRule(true, flowRule);
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800711 }
712
713 /**
714 * Populates rules for local in port in IN_PORT table.
715 * Flows from a given in port, whose source IP is service IP transition
716 * to DST_TYPE table. Other flows transition to IN_SERVICE table.
717 *
718 * @param deviceId device id to install the rules
719 * @param inPort in port
720 * @param srcIp source ip
721 */
722 private void populateLocalInPortRule(DeviceId deviceId, PortNumber inPort, IpAddress srcIp) {
723 TrafficSelector selector = DefaultTrafficSelector.builder()
724 .matchInPort(inPort)
725 .matchEthType(Ethernet.TYPE_IPV4)
726 .matchIPSrc(srcIp.toIpPrefix())
727 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800728
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800729 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
730 .transition(TABLE_ACCESS_TYPE)
731 .build();
732
733
734 FlowRule flowRule = DefaultFlowRule.builder()
735 .fromApp(appId)
736 .withSelector(selector)
737 .withTreatment(treatment)
738 .withPriority(DEFAULT_PRIORITY)
739 .forDevice(deviceId)
740 .forTable(TABLE_IN_PORT)
741 .makePermanent()
742 .build();
743
744 processFlowRule(true, flowRule);
745
746 selector = DefaultTrafficSelector.builder()
747 .matchInPort(inPort)
748 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800749
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800750 treatment = DefaultTrafficTreatment.builder()
751 .transition(TABLE_IN_SERVICE)
752 .build();
753
754 flowRule = DefaultFlowRule.builder()
755 .fromApp(appId)
756 .withSelector(selector)
757 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800758 .withPriority(LOW_PRIORITY)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800759 .forDevice(deviceId)
760 .forTable(TABLE_IN_PORT)
761 .makePermanent()
762 .build();
763
764 processFlowRule(true, flowRule);
765 }
766
767 /**
768 * Populates direct VM access rules for ACCESS_TYPE table.
769 * These rules are installed to all devices.
770 *
771 * @param srcRange source ip range
772 * @param dstRange destination ip range
773 */
774 private void populateDirectAccessRule(Ip4Prefix srcRange, Ip4Prefix dstRange) {
775 TrafficSelector selector = DefaultTrafficSelector.builder()
776 .matchEthType(Ethernet.TYPE_IPV4)
777 .matchIPSrc(srcRange)
778 .matchIPDst(dstRange)
779 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800780
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800781 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
782 .transition(TABLE_DST_IP)
783 .build();
784
785 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
786 FlowRule flowRuleDirect = DefaultFlowRule.builder()
787 .fromApp(appId)
788 .withSelector(selector)
789 .withTreatment(treatment)
Hyunsun Moon81ab23b2016-02-01 23:00:56 -0800790 .withPriority(DEFAULT_PRIORITY)
791 .forDevice(device.id())
792 .forTable(TABLE_ACCESS_TYPE)
793 .makePermanent()
794 .build();
795
796 processFlowRule(true, flowRuleDirect);
797 }
798 }
799
800 /**
801 * Populates drop rules that does not match any direct access rules but has
802 * destination to a different service network in ACCESS_TYPE table.
803 *
804 * @param dstRange destination ip range
805 */
806 private void populateServiceIsolationRule(Ip4Prefix dstRange) {
807 TrafficSelector selector = DefaultTrafficSelector.builder()
808 .matchEthType(Ethernet.TYPE_IPV4)
809 .matchIPDst(dstRange)
810 .build();
811
812 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
813 .drop()
814 .build();
815
816 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
817 FlowRule flowRuleDirect = DefaultFlowRule.builder()
818 .fromApp(appId)
819 .withSelector(selector)
820 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800821 .withPriority(LOW_PRIORITY)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800822 .forDevice(device.id())
823 .forTable(TABLE_ACCESS_TYPE)
824 .makePermanent()
825 .build();
826
827 processFlowRule(true, flowRuleDirect);
828 }
829 }
830
831 /**
832 * Populates indirect service access rules for ACCESS_TYPE table.
833 * These rules are installed to all devices.
834 *
835 * @param srcRange source range
836 * @param serviceIp service ip
837 * @param outGroups list of output group
838 */
839 private void populateIndirectAccessRule(Ip4Prefix srcRange, Ip4Address serviceIp,
840 Map<DeviceId, GroupId> outGroups) {
841 TrafficSelector selector = DefaultTrafficSelector.builder()
842 .matchEthType(Ethernet.TYPE_IPV4)
843 .matchIPSrc(srcRange)
844 .matchIPDst(serviceIp.toIpPrefix())
845 .build();
846
847 for (Map.Entry<DeviceId, GroupId> outGroup : outGroups.entrySet()) {
848 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
849 .group(outGroup.getValue())
850 .build();
851
852 FlowRule flowRule = DefaultFlowRule.builder()
853 .fromApp(appId)
854 .withSelector(selector)
855 .withTreatment(treatment)
Hyunsun Moon81ab23b2016-02-01 23:00:56 -0800856 .withPriority(HIGH_PRIORITY)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800857 .forDevice(outGroup.getKey())
858 .forTable(TABLE_ACCESS_TYPE)
859 .makePermanent()
860 .build();
861
862 processFlowRule(true, flowRule);
863 }
864 }
865
866 /**
867 * Populates flow rules for IN_SERVICE table.
868 *
869 * @param inPorts list of inports related to the service for each device
870 * @param outGroups set of output groups
871 */
872 private void populateInServiceRule(Map<DeviceId, Set<PortNumber>> inPorts, Map<DeviceId, GroupId> outGroups) {
873 checkNotNull(inPorts);
874 checkNotNull(outGroups);
875
876 for (Map.Entry<DeviceId, Set<PortNumber>> entry : inPorts.entrySet()) {
877 Set<PortNumber> ports = entry.getValue();
878 DeviceId deviceId = entry.getKey();
879
880 GroupId groupId = outGroups.get(deviceId);
881 if (groupId == null) {
882 continue;
883 }
884
885 ports.stream().forEach(port -> {
886 TrafficSelector selector = DefaultTrafficSelector.builder()
887 .matchInPort(port)
888 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800889
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800890 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
891 .group(groupId)
892 .build();
893
894 FlowRule flowRule = DefaultFlowRule.builder()
895 .fromApp(appId)
896 .withSelector(selector)
897 .withTreatment(treatment)
898 .withPriority(DEFAULT_PRIORITY)
899 .forDevice(deviceId)
900 .forTable(TABLE_IN_SERVICE)
901 .makePermanent()
902 .build();
903
904 processFlowRule(true, flowRule);
905 });
906 }
907 }
908
909 /**
910 * Populates flow rules for DST_IP table.
911 *
912 * @param deviceId device id
913 * @param inPort in port
914 * @param dstMac mac address
915 * @param dstIp destination ip
916 * @param tunnelId tunnel id
917 * @param tunnelIp tunnel remote ip
918 */
919 private void populateDstIpRule(DeviceId deviceId, PortNumber inPort, MacAddress dstMac,
920 IpAddress dstIp, long tunnelId, IpAddress tunnelIp) {
921 TrafficSelector selector = DefaultTrafficSelector.builder()
922 .matchEthType(Ethernet.TYPE_IPV4)
923 .matchIPDst(dstIp.toIpPrefix())
924 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800925
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800926 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
927 .setEthDst(dstMac)
928 .setOutput(inPort)
929 .build();
930
931 FlowRule flowRule = DefaultFlowRule.builder()
932 .fromApp(appId)
933 .withSelector(selector)
934 .withTreatment(treatment)
935 .withPriority(DEFAULT_PRIORITY)
936 .forDevice(deviceId)
937 .forTable(TABLE_DST_IP)
938 .makePermanent()
939 .build();
940
941 processFlowRule(true, flowRule);
942
943 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
944 if (device.id().equals(deviceId)) {
945 continue;
946 }
947
948 ExtensionTreatment tunnelDst = getTunnelDst(device.id(), tunnelIp.getIp4Address());
949 if (tunnelDst == null) {
950 continue;
951 }
952
953 treatment = DefaultTrafficTreatment.builder()
954 .setEthDst(dstMac)
955 .setTunnelId(tunnelId)
956 .extension(tunnelDst, device.id())
957 .setOutput(getTunnelPort(device.id()))
958 .build();
959
960 flowRule = DefaultFlowRule.builder()
961 .fromApp(appId)
962 .withSelector(selector)
963 .withTreatment(treatment)
964 .withPriority(DEFAULT_PRIORITY)
965 .forDevice(device.id())
966 .forTable(TABLE_DST_IP)
967 .makePermanent()
968 .build();
969
970 processFlowRule(true, flowRule);
971 }
972 }
973
974 /**
975 * Populates flow rules for TUNNEL_ID table.
976 *
977 * @param deviceId device id
978 * @param inPort in port
979 * @param mac mac address
980 * @param tunnelId tunnel id
981 */
982 private void populateTunnelInRule(DeviceId deviceId, PortNumber inPort, MacAddress mac, long tunnelId) {
983 TrafficSelector selector = DefaultTrafficSelector.builder()
984 .matchTunnelId(tunnelId)
985 .matchEthDst(mac)
986 .build();
987
988 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
989 .setOutput(inPort)
990 .build();
991
992 FlowRule flowRule = DefaultFlowRule.builder()
993 .fromApp(appId)
994 .withSelector(selector)
995 .withTreatment(treatment)
996 .withPriority(DEFAULT_PRIORITY)
997 .forDevice(deviceId)
998 .forTable(TABLE_TUNNEL_IN)
999 .makePermanent()
1000 .build();
1001
1002 processFlowRule(true, flowRule);
1003 }
1004
1005 /**
1006 * Installs or uninstall a given rule.
1007 *
1008 * @param install true to install, false to uninstall
1009 * @param rule rule
1010 */
1011 private void processFlowRule(boolean install, FlowRule rule) {
1012 FlowRuleOperations.Builder oBuilder = FlowRuleOperations.builder();
1013 oBuilder = install ? oBuilder.add(rule) : oBuilder.remove(rule);
1014
1015 flowRuleService.apply(oBuilder.build(new FlowRuleOperationsContext() {
1016 @Override
1017 public void onError(FlowRuleOperations ops) {
1018 log.error(String.format("Failed %s, %s", ops.toString(), rule.toString()));
1019 }
1020 }));
1021 }
1022
1023 /**
1024 * Returns tunnel port of the device.
1025 *
1026 * @param deviceId device id
1027 * @return tunnel port number, or null if no tunnel port exists on a given device
1028 */
1029 private PortNumber getTunnelPort(DeviceId deviceId) {
Hyunsun Moon5a4346f2016-01-15 11:41:14 -08001030 Port port = deviceService.getPorts(deviceId).stream()
Hyunsun Moon133fd792016-02-09 01:55:48 -08001031 .filter(p -> p.annotations().value(PORT_NAME).contains(tunnelType))
Hyunsun Moon5a4346f2016-01-15 11:41:14 -08001032 .findFirst().orElse(null);
1033
1034 return port == null ? null : port.number();
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001035 }
1036
1037 /**
Hyunsun Moon133fd792016-02-09 01:55:48 -08001038 * Returns data plane interface port name of a given device.
Hyunsun Moon4a915152016-01-14 16:56:26 -08001039 *
1040 * @param deviceId device id
Hyunsun Moon133fd792016-02-09 01:55:48 -08001041 * @param dpIntf data plane interface port name
1042 * @return data plane interface port number, or null if no such port exists
Hyunsun Moon4a915152016-01-14 16:56:26 -08001043 */
Hyunsun Moon133fd792016-02-09 01:55:48 -08001044 private PortNumber getDpPort(DeviceId deviceId, String dpIntf) {
Hyunsun Moon5a4346f2016-01-15 11:41:14 -08001045 Port port = deviceService.getPorts(deviceId).stream()
Hyunsun Moon133fd792016-02-09 01:55:48 -08001046 .filter(p -> p.annotations().value(PORT_NAME).contains(dpIntf) &&
Hyunsun Moon4a915152016-01-14 16:56:26 -08001047 p.isEnabled())
Hyunsun Moon5a4346f2016-01-15 11:41:14 -08001048 .findFirst().orElse(null);
1049
1050 return port == null ? null : port.number();
Hyunsun Moon4a915152016-01-14 16:56:26 -08001051 }
1052
1053 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001054 * Returns the inport from a given flow rule if the rule contains the match of it.
1055 *
1056 * @param flowRule flow rule
1057 * @return port number, or null if the rule doesn't have inport match
1058 */
1059 private PortNumber getInPort(FlowRule flowRule) {
1060 Criterion criterion = flowRule.selector().getCriterion(IN_PORT);
1061 if (criterion != null && criterion instanceof PortCriterion) {
1062 PortCriterion port = (PortCriterion) criterion;
1063 return port.port();
1064 } else {
1065 return null;
1066 }
1067 }
1068
1069 /**
1070 * Returns the destination mac address from a given flow rule if the rule
1071 * contains the instruction of it.
1072 *
1073 * @param flowRule flow rule
1074 * @return mac address, or null if the rule doesn't have destination mac instruction
1075 */
1076 private MacAddress getDstMacFromTreatment(FlowRule flowRule) {
1077 Instruction instruction = flowRule.treatment().allInstructions().stream()
1078 .filter(inst -> inst instanceof ModEtherInstruction &&
1079 ((ModEtherInstruction) inst).subtype().equals(ETH_DST))
1080 .findFirst()
1081 .orElse(null);
1082
1083 if (instruction == null) {
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001084 return null;
1085 }
1086
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001087 return ((ModEtherInstruction) instruction).mac();
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001088 }
1089
1090 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001091 * Returns the destination mac address from a given flow rule if the rule
1092 * contains the match of it.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001093 *
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001094 * @param flowRule flow rule
1095 * @return mac address, or null if the rule doesn't have destination mac match
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001096 */
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001097 private MacAddress getDstMacFromSelector(FlowRule flowRule) {
1098 Criterion criterion = flowRule.selector().getCriterion(Criterion.Type.ETH_DST);
1099 if (criterion != null && criterion instanceof EthCriterion) {
1100 EthCriterion eth = (EthCriterion) criterion;
1101 return eth.mac();
1102 } else {
1103 return null;
1104 }
1105 }
1106
1107 /**
1108 * Returns the destination IP from a given flow rule if the rule contains
1109 * the match of it.
1110 *
1111 * @param flowRule flow rule
1112 * @return ip prefix, or null if the rule doesn't have ip match
1113 */
1114 private IpPrefix getDstIpFromSelector(FlowRule flowRule) {
1115 Criterion criterion = flowRule.selector().getCriterion(IPV4_DST);
1116 if (criterion != null && criterion instanceof IPCriterion) {
1117 IPCriterion ip = (IPCriterion) criterion;
1118 return ip.ip();
1119 } else {
1120 return null;
1121 }
1122 }
1123
1124 /**
1125 * Returns the source IP from a given flow rule if the rule contains
1126 * the match of it.
1127 *
1128 * @param flowRule flow rule
1129 * @return ip prefix, or null if the rule doesn't have ip match
1130 */
1131 private IpPrefix getSrcIpFromSelector(FlowRule flowRule) {
1132 Criterion criterion = flowRule.selector().getCriterion(IPV4_SRC);
1133 if (criterion != null && criterion instanceof IPCriterion) {
1134 IPCriterion ip = (IPCriterion) criterion;
1135 return ip.ip();
1136 } else {
1137 return null;
1138 }
1139 }
1140
1141 /**
1142 * Returns the group ID from a given flow rule if the rule contains the
1143 * treatment of it.
1144 *
1145 * @param flowRule flow rule
1146 * @return group id, or null if the rule doesn't have group instruction
1147 */
1148 private GroupId getGroupIdFromTreatment(FlowRule flowRule) {
1149 Instruction instruction = flowRule.treatment().allInstructions().stream()
1150 .filter(inst -> inst instanceof Instructions.GroupInstruction)
1151 .findFirst()
1152 .orElse(null);
1153
1154 if (instruction == null) {
1155 return null;
1156 }
1157
1158 return ((Instructions.GroupInstruction) instruction).groupId();
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001159 }
1160
1161 /**
Hyunsun Moond52bffc2016-01-29 18:57:05 -08001162 * Returns the output port number from a given flow rule.
1163 *
1164 * @param flowRule flow rule
1165 * @return port number, or null if the rule does not have output instruction
1166 */
1167 private PortNumber getOutputFromTreatment(FlowRule flowRule) {
1168 Instruction instruction = flowRule.treatment().allInstructions().stream()
1169 .filter(inst -> inst instanceof Instructions.OutputInstruction)
1170 .findFirst()
1171 .orElse(null);
1172
1173 if (instruction == null) {
1174 return null;
1175 }
1176
1177 return ((Instructions.OutputInstruction) instruction).port();
1178 }
1179
1180 /**
Hyunsun Moon4a915152016-01-14 16:56:26 -08001181 * Creates a new group for a given service.
1182 *
1183 * @param deviceId device id to create a group
1184 * @param service cord service
1185 * @return group id, or null if it fails to create
1186 */
1187 private GroupId createServiceGroup(DeviceId deviceId, CordService service) {
1188 checkNotNull(service);
1189
1190 GroupKey groupKey = getGroupKey(service.id());
1191 Group group = groupService.getGroup(deviceId, groupKey);
1192 GroupId groupId = getGroupId(service.id(), deviceId);
1193
1194 if (group != null) {
1195 log.debug("Group {} is already exist in {}", service.id(), deviceId);
1196 return groupId;
1197 }
1198
1199 GroupBuckets buckets = getServiceGroupBuckets(deviceId, service.segmentationId(), service.hosts());
1200 GroupDescription groupDescription = new DefaultGroupDescription(
1201 deviceId,
1202 GroupDescription.Type.SELECT,
1203 buckets,
1204 groupKey,
1205 groupId.id(),
1206 appId);
1207
1208 groupService.addGroup(groupDescription);
1209
1210 return groupId;
1211 }
1212
1213 /**
1214 * Returns group buckets for a given device.
1215 *
1216 * @param deviceId device id
1217 * @param tunnelId tunnel id
1218 * @param hosts list of host
1219 * @return group buckets
1220 */
1221 private GroupBuckets getServiceGroupBuckets(DeviceId deviceId, long tunnelId, Map<Host, IpAddress> hosts) {
1222 List<GroupBucket> buckets = Lists.newArrayList();
1223
1224 for (Map.Entry<Host, IpAddress> entry : hosts.entrySet()) {
1225 Host host = entry.getKey();
1226 Ip4Address remoteIp = entry.getValue().getIp4Address();
1227 DeviceId hostDevice = host.location().deviceId();
1228
1229 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
1230 .builder()
1231 .setEthDst(host.mac());
1232
1233 if (deviceId.equals(hostDevice)) {
1234 tBuilder.setOutput(host.location().port());
1235 } else {
1236 ExtensionTreatment tunnelDst = getTunnelDst(deviceId, remoteIp);
1237 if (tunnelDst == null) {
1238 continue;
1239 }
1240
1241 tBuilder.extension(tunnelDst, deviceId)
1242 .setTunnelId(tunnelId)
1243 .setOutput(getTunnelPort(hostDevice));
1244 }
1245
1246 buckets.add(DefaultGroupBucket.createSelectGroupBucket(tBuilder.build()));
1247 }
1248
1249 return new GroupBuckets(buckets);
1250 }
1251
1252 /**
1253 * Returns globally unique group ID.
1254 *
1255 * @param serviceId service id
1256 * @param deviceId device id
1257 * @return group id
1258 */
1259 private GroupId getGroupId(CordServiceId serviceId, DeviceId deviceId) {
1260 return new DefaultGroupId(Objects.hash(serviceId, deviceId));
1261 }
1262
1263 /**
1264 * Returns group key of a service.
1265 *
1266 * @param serviceId service id
1267 * @return group key
1268 */
1269 private GroupKey getGroupKey(CordServiceId serviceId) {
1270 return new DefaultGroupKey(serviceId.id().getBytes());
1271 }
1272
1273 /**
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001274 * Returns extension instruction to set tunnel destination.
1275 *
1276 * @param deviceId device id
1277 * @param remoteIp tunnel destination address
1278 * @return extension treatment or null if it fails to get instruction
1279 */
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001280 private ExtensionTreatment getTunnelDst(DeviceId deviceId, Ip4Address remoteIp) {
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001281 try {
1282 Driver driver = driverService.getDriver(deviceId);
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001283 DefaultDriverData driverData = new DefaultDriverData(driver, deviceId);
1284 DriverHandler handler = new DefaultDriverHandler(driverData);
1285 ExtensionTreatmentResolver resolver = handler.behaviour(ExtensionTreatmentResolver.class);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001286
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001287 ExtensionTreatment treatment =
1288 resolver.getExtensionInstruction(NICIRA_SET_TUNNEL_DST.type());
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001289 treatment.setPropertyValue("tunnelDst", remoteIp);
1290
1291 return treatment;
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001292 } catch (ItemNotFoundException | UnsupportedOperationException |
1293 ExtensionPropertyException e) {
1294 log.error("Failed to get extension instruction {}", deviceId);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001295 return null;
1296 }
1297 }
1298}
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001299