blob: b2451d4785771c85618d356614ad4eff66f1e562 [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 Moon4a915152016-01-14 16:56:26 -080099 private static final int TABLE_FIRST = 0;
100 private static final int TABLE_IN_PORT = 1;
101 private static final int TABLE_ACCESS_TYPE = 2;
102 private static final int TABLE_IN_SERVICE = 3;
103 private static final int TABLE_DST_IP = 4;
104 private static final int TABLE_TUNNEL_IN = 5;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800105
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800106 private static final int MANAGEMENT_PRIORITY = 55000;
107 private static final int HIGH_PRIORITY = 50000;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800108 private static final int DEFAULT_PRIORITY = 5000;
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800109 private static final int LOW_PRIORITY = 4000;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800110 private static final int LOWEST_PRIORITY = 0;
Hyunsun Moon4a915152016-01-14 16:56:26 -0800111
112 private static final int VXLAN_UDP_PORT = 4789;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800113
114 private final ApplicationId appId;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800115 private final FlowRuleService flowRuleService;
116 private final DeviceService deviceService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800117 private final DriverService driverService;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800118 private final GroupService groupService;
119 private final MastershipService mastershipService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800120 private final String tunnelType;
121
122 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800123 * Creates a new rule populator.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800124 *
125 * @param appId application id
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800126 * @param flowRuleService flow rule service
127 * @param deviceService device service
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800128 * @param driverService driver service
Jian Lidfba7392016-01-22 16:46:58 -0800129 * @param groupService group service
130 * @param mastershipService mastership service
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800131 * @param tunnelType tunnel type
132 */
133 public CordVtnRuleInstaller(ApplicationId appId,
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800134 FlowRuleService flowRuleService,
135 DeviceService deviceService,
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800136 DriverService driverService,
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800137 GroupService groupService,
138 MastershipService mastershipService,
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800139 String tunnelType) {
140 this.appId = appId;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800141 this.flowRuleService = flowRuleService;
142 this.deviceService = deviceService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800143 this.driverService = driverService;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800144 this.groupService = groupService;
145 this.mastershipService = mastershipService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800146 this.tunnelType = checkNotNull(tunnelType);
147 }
148
149 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800150 * Installs table miss rule to a give device.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800151 *
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800152 * @param deviceId device id to install the rules
Hyunsun Moon4a915152016-01-14 16:56:26 -0800153 * @param phyPortName physical port name
154 * @param localIp local data plane ip address
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800155 */
Hyunsun Moon4a915152016-01-14 16:56:26 -0800156 public void init(DeviceId deviceId, String phyPortName, IpAddress localIp) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800157 // default is drop packets which can be accomplished without
158 // a table miss entry for all table.
Hyunsun Moon4a915152016-01-14 16:56:26 -0800159 PortNumber tunnelPort = getTunnelPort(deviceId);
160 PortNumber phyPort = getPhyPort(deviceId, phyPortName);
161
162 processFirstTable(deviceId, phyPort, localIp);
163 processInPortTable(deviceId, tunnelPort, phyPort);
164 processAccessTypeTable(deviceId, phyPort);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800165 }
166
167 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800168 * Populates basic rules that connect a VM to the other VMs in the system.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800169 *
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800170 * @param host host
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800171 * @param tunnelIp tunnel ip
172 * @param vNet openstack network
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800173 */
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800174 public void populateBasicConnectionRules(Host host, IpAddress tunnelIp, OpenstackNetwork vNet) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800175 checkNotNull(host);
176 checkNotNull(vNet);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800177
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800178 DeviceId deviceId = host.location().deviceId();
179 if (!mastershipService.isLocalMaster(deviceId)) {
180 return;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800181 }
182
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800183 PortNumber inPort = host.location().port();
184 MacAddress dstMac = host.mac();
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800185 IpAddress hostIp = host.ipAddresses().stream().findFirst().get();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800186 long tunnelId = Long.parseLong(vNet.segmentId());
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800187
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800188 OpenstackSubnet subnet = vNet.subnets().stream()
189 .findFirst()
190 .orElse(null);
191
192 if (subnet == null) {
193 log.error("Failed to get subnet for {}", host.id());
194 return;
195 }
196
197 populateLocalInPortRule(deviceId, inPort, hostIp);
198 populateDirectAccessRule(Ip4Prefix.valueOf(subnet.cidr()), Ip4Prefix.valueOf(subnet.cidr()));
199 populateDstIpRule(deviceId, inPort, dstMac, hostIp, tunnelId, tunnelIp);
200 populateTunnelInRule(deviceId, inPort, dstMac, tunnelId);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800201 }
202
203 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800204 * Removes basic rules related to a given flow information.
205 *
206 * @param host host to be removed
207 */
208 public void removeBasicConnectionRules(Host host) {
209 checkNotNull(host);
210
211 DeviceId deviceId = host.location().deviceId();
212 MacAddress mac = host.mac();
213 PortNumber port = host.location().port();
214 IpAddress ip = host.ipAddresses().stream().findFirst().orElse(null);
215
216 if (!mastershipService.isLocalMaster(deviceId)) {
217 return;
218 }
219
220 for (FlowRule flowRule : flowRuleService.getFlowRulesById(appId)) {
221 if (flowRule.deviceId().equals(deviceId)) {
222 PortNumber inPort = getInPort(flowRule);
223 if (inPort != null && inPort.equals(port)) {
224 processFlowRule(false, flowRule);
225 continue;
226 }
227 }
228
229 MacAddress dstMac = getDstMacFromTreatment(flowRule);
230 if (dstMac != null && dstMac.equals(mac)) {
231 processFlowRule(false, flowRule);
232 continue;
233 }
234
235 dstMac = getDstMacFromSelector(flowRule);
236 if (dstMac != null && dstMac.equals(mac)) {
237 processFlowRule(false, flowRule);
238 continue;
239 }
240
241 IpPrefix dstIp = getDstIpFromSelector(flowRule);
242 if (dstIp != null && dstIp.equals(ip.toIpPrefix())) {
243 processFlowRule(false, flowRule);
244 }
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800245 }
246
247 // TODO uninstall same network access rule in access table if no vm exists in the network
248 }
249
250 /**
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800251 * Populates service dependency rules.
252 *
253 * @param tService tenant cord service
254 * @param pService provider cord service
255 */
256 public void populateServiceDependencyRules(CordService tService, CordService pService) {
257 checkNotNull(tService);
258 checkNotNull(pService);
259
260 Ip4Prefix srcRange = tService.serviceIpRange().getIp4Prefix();
261 Ip4Prefix dstRange = pService.serviceIpRange().getIp4Prefix();
262 Ip4Address serviceIp = pService.serviceIp().getIp4Address();
263
264 Map<DeviceId, GroupId> outGroups = Maps.newHashMap();
265 Map<DeviceId, Set<PortNumber>> inPorts = Maps.newHashMap();
266
267 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
268 GroupId groupId = createServiceGroup(device.id(), pService);
269 outGroups.put(device.id(), groupId);
270
271 Set<PortNumber> vms = tService.hosts().keySet()
272 .stream()
273 .filter(host -> host.location().deviceId().equals(device.id()))
274 .map(host -> host.location().port())
275 .collect(Collectors.toSet());
276 inPorts.put(device.id(), vms);
277 }
278
279 populateIndirectAccessRule(srcRange, serviceIp, outGroups);
280 populateDirectAccessRule(srcRange, dstRange);
281 populateInServiceRule(inPorts, outGroups);
282 }
283
284 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800285 * Removes service dependency rules.
286 *
287 * @param tService tenant cord service
288 * @param pService provider cord service
289 */
290 public void removeServiceDependencyRules(CordService tService, CordService pService) {
291 checkNotNull(tService);
292 checkNotNull(pService);
293
294 Ip4Prefix srcRange = tService.serviceIpRange().getIp4Prefix();
295 Ip4Prefix dstRange = pService.serviceIpRange().getIp4Prefix();
296 IpPrefix serviceIp = pService.serviceIp().toIpPrefix();
297
298 Map<DeviceId, GroupId> outGroups = Maps.newHashMap();
299 GroupKey groupKey = new DefaultGroupKey(pService.id().id().getBytes());
300
301 deviceService.getAvailableDevices(SWITCH).forEach(device -> {
302 Group group = groupService.getGroup(device.id(), groupKey);
303 if (group != null) {
304 outGroups.put(device.id(), group.id());
305 }
306 });
307
308 for (FlowRule flowRule : flowRuleService.getFlowRulesById(appId)) {
309 IpPrefix dstIp = getDstIpFromSelector(flowRule);
310 IpPrefix srcIp = getSrcIpFromSelector(flowRule);
311
312 if (dstIp != null && dstIp.equals(serviceIp)) {
313 processFlowRule(false, flowRule);
314 continue;
315 }
316
317 if (dstIp != null && srcIp != null) {
318 if (dstIp.equals(dstRange) && srcIp.equals(srcRange)) {
319 processFlowRule(false, flowRule);
320 continue;
321 }
322
323 if (dstIp.equals(srcRange) && srcIp.equals(dstRange)) {
324 processFlowRule(false, flowRule);
325 continue;
326 }
327 }
328
329 GroupId groupId = getGroupIdFromTreatment(flowRule);
330 if (groupId != null && groupId.equals(outGroups.get(flowRule.deviceId()))) {
331 processFlowRule(false, flowRule);
332 }
333 }
334
335 // TODO remove the group if it is not in use
336 }
337
338 /**
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800339 * Updates group buckets for a given service to all devices.
340 *
341 * @param service cord service
342 */
343 public void updateServiceGroup(CordService service) {
344 checkNotNull(service);
345
346 GroupKey groupKey = getGroupKey(service.id());
347
348 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
349 DeviceId deviceId = device.id();
350 if (!mastershipService.isLocalMaster(deviceId)) {
351 continue;
352 }
353
354 Group group = groupService.getGroup(deviceId, groupKey);
355 if (group == null) {
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800356 log.trace("No group exists for service {} in {}, do nothing.", service.id(), deviceId);
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800357 continue;
358 }
359
360 List<GroupBucket> oldBuckets = group.buckets().buckets();
361 List<GroupBucket> newBuckets = getServiceGroupBuckets(
362 deviceId, service.segmentationId(), service.hosts()).buckets();
363
364 if (oldBuckets.equals(newBuckets)) {
365 continue;
366 }
367
368 List<GroupBucket> bucketsToRemove = new ArrayList<>(oldBuckets);
369 bucketsToRemove.removeAll(newBuckets);
370 if (!bucketsToRemove.isEmpty()) {
371 groupService.removeBucketsFromGroup(
372 deviceId,
373 groupKey,
374 new GroupBuckets(bucketsToRemove),
375 groupKey, appId);
376 }
377
378 List<GroupBucket> bucketsToAdd = new ArrayList<>(newBuckets);
379 bucketsToAdd.removeAll(oldBuckets);
380 if (!bucketsToAdd.isEmpty()) {
381 groupService.addBucketsToGroup(
382 deviceId,
383 groupKey,
384 new GroupBuckets(bucketsToAdd),
385 groupKey, appId);
386 }
387 }
388 }
389
390 /**
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800391 * Populates flow rules for management network access.
392 *
393 * @param host host which has management network interface
394 * @param mService management network service
395 */
396 public void populateManagementNetworkRules(Host host, CordService mService) {
397 checkNotNull(mService);
398
399 DeviceId deviceId = host.location().deviceId();
400 IpAddress hostIp = host.ipAddresses().stream().findFirst().get();
401
402 TrafficSelector selector = DefaultTrafficSelector.builder()
403 .matchEthType(Ethernet.TYPE_ARP)
404 .matchArpTpa(mService.serviceIp().getIp4Address())
405 .build();
406
407 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
408 .setOutput(PortNumber.LOCAL)
409 .build();
410
411 FlowRule flowRule = DefaultFlowRule.builder()
412 .fromApp(appId)
413 .withSelector(selector)
414 .withTreatment(treatment)
415 .withPriority(MANAGEMENT_PRIORITY)
416 .forDevice(deviceId)
417 .forTable(TABLE_FIRST)
418 .makePermanent()
419 .build();
420
421 processFlowRule(true, flowRule);
422
423 selector = DefaultTrafficSelector.builder()
424 .matchInPort(PortNumber.LOCAL)
425 .matchEthType(Ethernet.TYPE_ARP)
426 .matchArpTpa(hostIp.getIp4Address())
427 .build();
428
429 treatment = DefaultTrafficTreatment.builder()
430 .setOutput(host.location().port())
431 .build();
432
433 flowRule = DefaultFlowRule.builder()
434 .fromApp(appId)
435 .withSelector(selector)
436 .withTreatment(treatment)
437 .withPriority(MANAGEMENT_PRIORITY)
438 .forDevice(deviceId)
439 .forTable(TABLE_FIRST)
440 .makePermanent()
441 .build();
442
443 processFlowRule(true, flowRule);
444
445 selector = DefaultTrafficSelector.builder()
446 .matchInPort(PortNumber.LOCAL)
447 .matchEthType(Ethernet.TYPE_IPV4)
448 .matchIPDst(mService.serviceIpRange())
449 .build();
450
451 treatment = DefaultTrafficTreatment.builder()
452 .transition(TABLE_DST_IP)
453 .build();
454
455 flowRule = DefaultFlowRule.builder()
456 .fromApp(appId)
457 .withSelector(selector)
458 .withTreatment(treatment)
459 .withPriority(MANAGEMENT_PRIORITY)
460 .forDevice(deviceId)
461 .forTable(TABLE_FIRST)
462 .makePermanent()
463 .build();
464
465 processFlowRule(true, flowRule);
466
467 selector = DefaultTrafficSelector.builder()
468 .matchEthType(Ethernet.TYPE_IPV4)
469 .matchIPDst(mService.serviceIp().toIpPrefix())
470 .build();
471
472 treatment = DefaultTrafficTreatment.builder()
473 .setOutput(PortNumber.LOCAL)
474 .build();
475
476 flowRule = DefaultFlowRule.builder()
477 .fromApp(appId)
478 .withSelector(selector)
479 .withTreatment(treatment)
480 .withPriority(MANAGEMENT_PRIORITY)
481 .forDevice(deviceId)
482 .forTable(TABLE_ACCESS_TYPE)
483 .makePermanent()
484 .build();
485
486 processFlowRule(true, flowRule);
487 }
488
489 /**
490 * Removes management network access rules.
491 *
492 * @param host host to be removed
493 * @param mService service for management network
494 */
495 public void removeManagementNetworkRules(Host host, CordService mService) {
496 checkNotNull(mService);
497
498 for (FlowRule flowRule : flowRuleService.getFlowRulesById(appId)) {
499 if (flowRule.deviceId().equals(host.location().deviceId())) {
500 PortNumber port = getOutputFromTreatment(flowRule);
501 if (port != null && port.equals(host.location().port())) {
502 processFlowRule(false, flowRule);
503 }
504 }
505
506 // TODO remove the other rules if mgmt network is not in use
507 }
508 }
509
510 /**
Hyunsun Moon4a915152016-01-14 16:56:26 -0800511 * Populates default rules on the first table.
512 * The rules are for shuttling vxlan-encapped packets and supporting physical
513 * network connectivity.
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800514 *
515 * @param deviceId device id
Hyunsun Moon4a915152016-01-14 16:56:26 -0800516 * @param phyPort physical port number
517 * @param localIp local data plane ip address
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800518 */
Hyunsun Moon4a915152016-01-14 16:56:26 -0800519 private void processFirstTable(DeviceId deviceId, PortNumber phyPort, IpAddress localIp) {
520 // take vxlan packet out onto the physical port
521 TrafficSelector selector = DefaultTrafficSelector.builder()
522 .matchInPort(PortNumber.LOCAL)
523 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800524
Hyunsun Moon4a915152016-01-14 16:56:26 -0800525 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
526 .setOutput(phyPort)
527 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800528
Hyunsun Moon4a915152016-01-14 16:56:26 -0800529 FlowRule flowRule = DefaultFlowRule.builder()
530 .fromApp(appId)
531 .withSelector(selector)
532 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800533 .withPriority(HIGH_PRIORITY)
Hyunsun Moon4a915152016-01-14 16:56:26 -0800534 .forDevice(deviceId)
535 .forTable(TABLE_FIRST)
536 .makePermanent()
537 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800538
Hyunsun Moon4a915152016-01-14 16:56:26 -0800539 processFlowRule(true, flowRule);
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800540
Hyunsun Moon4a915152016-01-14 16:56:26 -0800541 // take a vxlan encap'd packet through the Linux stack
542 selector = DefaultTrafficSelector.builder()
543 .matchInPort(phyPort)
544 .matchEthType(Ethernet.TYPE_IPV4)
545 .matchIPProtocol(IPv4.PROTOCOL_UDP)
546 .matchUdpDst(TpPort.tpPort(VXLAN_UDP_PORT))
547 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800548
Hyunsun Moon4a915152016-01-14 16:56:26 -0800549 treatment = DefaultTrafficTreatment.builder()
550 .setOutput(PortNumber.LOCAL)
551 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800552
Hyunsun Moon4a915152016-01-14 16:56:26 -0800553 flowRule = DefaultFlowRule.builder()
554 .fromApp(appId)
555 .withSelector(selector)
556 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800557 .withPriority(HIGH_PRIORITY)
Hyunsun Moon4a915152016-01-14 16:56:26 -0800558 .forDevice(deviceId)
559 .forTable(TABLE_FIRST)
560 .makePermanent()
561 .build();
562
563 processFlowRule(true, flowRule);
564
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800565 // take a packet to the local ip through Linux stack
566 selector = DefaultTrafficSelector.builder()
567 .matchInPort(phyPort)
568 .matchEthType(Ethernet.TYPE_IPV4)
569 .matchIPDst(localIp.toIpPrefix())
570 .build();
571
572 treatment = DefaultTrafficTreatment.builder()
573 .setOutput(PortNumber.LOCAL)
574 .build();
575
576 flowRule = DefaultFlowRule.builder()
577 .fromApp(appId)
578 .withSelector(selector)
579 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800580 .withPriority(HIGH_PRIORITY)
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800581 .forDevice(deviceId)
582 .forTable(TABLE_FIRST)
583 .makePermanent()
584 .build();
585
586 processFlowRule(true, flowRule);
587
588 // take an arp packet from physical through Linux stack
589 selector = DefaultTrafficSelector.builder()
590 .matchInPort(phyPort)
591 .matchEthType(Ethernet.TYPE_ARP)
592 .build();
593
594 treatment = DefaultTrafficTreatment.builder()
595 .setOutput(PortNumber.LOCAL)
596 .build();
597
598 flowRule = DefaultFlowRule.builder()
599 .fromApp(appId)
600 .withSelector(selector)
601 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800602 .withPriority(HIGH_PRIORITY)
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800603 .forDevice(deviceId)
604 .forTable(TABLE_FIRST)
605 .makePermanent()
606 .build();
607
608 processFlowRule(true, flowRule);
609
Hyunsun Moon4a915152016-01-14 16:56:26 -0800610 // take all else to the next table
611 selector = DefaultTrafficSelector.builder()
612 .build();
613
614 treatment = DefaultTrafficTreatment.builder()
615 .transition(TABLE_IN_PORT)
616 .build();
617
618 flowRule = DefaultFlowRule.builder()
619 .fromApp(appId)
620 .withSelector(selector)
621 .withTreatment(treatment)
622 .withPriority(LOWEST_PRIORITY)
623 .forDevice(deviceId)
624 .forTable(TABLE_FIRST)
625 .makePermanent()
626 .build();
627
628 processFlowRule(true, flowRule);
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800629 }
630
631 /**
Hyunsun Moon4a915152016-01-14 16:56:26 -0800632 * Forward table miss packets in ACCESS_TYPE table to physical port.
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800633 *
634 * @param deviceId device id
Hyunsun Moon4a915152016-01-14 16:56:26 -0800635 * @param phyPort physical port number
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800636 */
Hyunsun Moon4a915152016-01-14 16:56:26 -0800637 private void processAccessTypeTable(DeviceId deviceId, PortNumber phyPort) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800638 TrafficSelector selector = DefaultTrafficSelector.builder()
639 .build();
640
641 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Hyunsun Moon4a915152016-01-14 16:56:26 -0800642 .setOutput(phyPort)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800643 .build();
644
645 FlowRule flowRule = DefaultFlowRule.builder()
646 .fromApp(appId)
647 .withSelector(selector)
648 .withTreatment(treatment)
649 .withPriority(LOWEST_PRIORITY)
650 .forDevice(deviceId)
651 .forTable(TABLE_ACCESS_TYPE)
652 .makePermanent()
653 .build();
654
655 processFlowRule(true, flowRule);
656 }
657
658 /**
Hyunsun Moon4a915152016-01-14 16:56:26 -0800659 * Populates default rules for IN_PORT table.
660 * All packets from tunnel port are forwarded to TUNNEL_ID table and all packets
661 * from physical port to ACCESS_TYPE table.
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800662 *
663 * @param deviceId device id to install the rules
Hyunsun Moon4a915152016-01-14 16:56:26 -0800664 * @param tunnelPort tunnel port number
665 * @param phyPort physical port number
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800666 */
Hyunsun Moon4a915152016-01-14 16:56:26 -0800667 private void processInPortTable(DeviceId deviceId, PortNumber tunnelPort, PortNumber phyPort) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800668 checkNotNull(tunnelPort);
669
670 TrafficSelector selector = DefaultTrafficSelector.builder()
671 .matchInPort(tunnelPort)
672 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800673
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800674 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
675 .transition(TABLE_TUNNEL_IN)
676 .build();
677
678 FlowRule flowRule = DefaultFlowRule.builder()
679 .fromApp(appId)
680 .withSelector(selector)
681 .withTreatment(treatment)
682 .withPriority(DEFAULT_PRIORITY)
683 .forDevice(deviceId)
684 .forTable(TABLE_IN_PORT)
685 .makePermanent()
686 .build();
687
688 processFlowRule(true, flowRule);
Hyunsun Moon4a915152016-01-14 16:56:26 -0800689
690 selector = DefaultTrafficSelector.builder()
691 .matchInPort(phyPort)
692 .build();
693
694 treatment = DefaultTrafficTreatment.builder()
695 .transition(TABLE_DST_IP)
696 .build();
697
698 flowRule = DefaultFlowRule.builder()
699 .fromApp(appId)
700 .withSelector(selector)
701 .withTreatment(treatment)
702 .withPriority(DEFAULT_PRIORITY)
703 .forDevice(deviceId)
704 .forTable(TABLE_IN_PORT)
705 .makePermanent()
706 .build();
707
708 processFlowRule(true, flowRule);
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800709 }
710
711 /**
712 * Populates rules for local in port in IN_PORT table.
713 * Flows from a given in port, whose source IP is service IP transition
714 * to DST_TYPE table. Other flows transition to IN_SERVICE table.
715 *
716 * @param deviceId device id to install the rules
717 * @param inPort in port
718 * @param srcIp source ip
719 */
720 private void populateLocalInPortRule(DeviceId deviceId, PortNumber inPort, IpAddress srcIp) {
721 TrafficSelector selector = DefaultTrafficSelector.builder()
722 .matchInPort(inPort)
723 .matchEthType(Ethernet.TYPE_IPV4)
724 .matchIPSrc(srcIp.toIpPrefix())
725 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800726
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800727 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
728 .transition(TABLE_ACCESS_TYPE)
729 .build();
730
731
732 FlowRule flowRule = DefaultFlowRule.builder()
733 .fromApp(appId)
734 .withSelector(selector)
735 .withTreatment(treatment)
736 .withPriority(DEFAULT_PRIORITY)
737 .forDevice(deviceId)
738 .forTable(TABLE_IN_PORT)
739 .makePermanent()
740 .build();
741
742 processFlowRule(true, flowRule);
743
744 selector = DefaultTrafficSelector.builder()
745 .matchInPort(inPort)
746 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800747
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800748 treatment = DefaultTrafficTreatment.builder()
749 .transition(TABLE_IN_SERVICE)
750 .build();
751
752 flowRule = DefaultFlowRule.builder()
753 .fromApp(appId)
754 .withSelector(selector)
755 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800756 .withPriority(LOW_PRIORITY)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800757 .forDevice(deviceId)
758 .forTable(TABLE_IN_PORT)
759 .makePermanent()
760 .build();
761
762 processFlowRule(true, flowRule);
763 }
764
765 /**
766 * Populates direct VM access rules for ACCESS_TYPE table.
767 * These rules are installed to all devices.
768 *
769 * @param srcRange source ip range
770 * @param dstRange destination ip range
771 */
772 private void populateDirectAccessRule(Ip4Prefix srcRange, Ip4Prefix dstRange) {
773 TrafficSelector selector = DefaultTrafficSelector.builder()
774 .matchEthType(Ethernet.TYPE_IPV4)
775 .matchIPSrc(srcRange)
776 .matchIPDst(dstRange)
777 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800778
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800779 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
780 .transition(TABLE_DST_IP)
781 .build();
782
783 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
784 FlowRule flowRuleDirect = DefaultFlowRule.builder()
785 .fromApp(appId)
786 .withSelector(selector)
787 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800788 .withPriority(LOW_PRIORITY)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800789 .forDevice(device.id())
790 .forTable(TABLE_ACCESS_TYPE)
791 .makePermanent()
792 .build();
793
794 processFlowRule(true, flowRuleDirect);
795 }
796 }
797
798 /**
799 * Populates indirect service access rules for ACCESS_TYPE table.
800 * These rules are installed to all devices.
801 *
802 * @param srcRange source range
803 * @param serviceIp service ip
804 * @param outGroups list of output group
805 */
806 private void populateIndirectAccessRule(Ip4Prefix srcRange, Ip4Address serviceIp,
807 Map<DeviceId, GroupId> outGroups) {
808 TrafficSelector selector = DefaultTrafficSelector.builder()
809 .matchEthType(Ethernet.TYPE_IPV4)
810 .matchIPSrc(srcRange)
811 .matchIPDst(serviceIp.toIpPrefix())
812 .build();
813
814 for (Map.Entry<DeviceId, GroupId> outGroup : outGroups.entrySet()) {
815 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
816 .group(outGroup.getValue())
817 .build();
818
819 FlowRule flowRule = DefaultFlowRule.builder()
820 .fromApp(appId)
821 .withSelector(selector)
822 .withTreatment(treatment)
823 .withPriority(DEFAULT_PRIORITY)
824 .forDevice(outGroup.getKey())
825 .forTable(TABLE_ACCESS_TYPE)
826 .makePermanent()
827 .build();
828
829 processFlowRule(true, flowRule);
830 }
831 }
832
833 /**
834 * Populates flow rules for IN_SERVICE table.
835 *
836 * @param inPorts list of inports related to the service for each device
837 * @param outGroups set of output groups
838 */
839 private void populateInServiceRule(Map<DeviceId, Set<PortNumber>> inPorts, Map<DeviceId, GroupId> outGroups) {
840 checkNotNull(inPorts);
841 checkNotNull(outGroups);
842
843 for (Map.Entry<DeviceId, Set<PortNumber>> entry : inPorts.entrySet()) {
844 Set<PortNumber> ports = entry.getValue();
845 DeviceId deviceId = entry.getKey();
846
847 GroupId groupId = outGroups.get(deviceId);
848 if (groupId == null) {
849 continue;
850 }
851
852 ports.stream().forEach(port -> {
853 TrafficSelector selector = DefaultTrafficSelector.builder()
854 .matchInPort(port)
855 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800856
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800857 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
858 .group(groupId)
859 .build();
860
861 FlowRule flowRule = DefaultFlowRule.builder()
862 .fromApp(appId)
863 .withSelector(selector)
864 .withTreatment(treatment)
865 .withPriority(DEFAULT_PRIORITY)
866 .forDevice(deviceId)
867 .forTable(TABLE_IN_SERVICE)
868 .makePermanent()
869 .build();
870
871 processFlowRule(true, flowRule);
872 });
873 }
874 }
875
876 /**
877 * Populates flow rules for DST_IP table.
878 *
879 * @param deviceId device id
880 * @param inPort in port
881 * @param dstMac mac address
882 * @param dstIp destination ip
883 * @param tunnelId tunnel id
884 * @param tunnelIp tunnel remote ip
885 */
886 private void populateDstIpRule(DeviceId deviceId, PortNumber inPort, MacAddress dstMac,
887 IpAddress dstIp, long tunnelId, IpAddress tunnelIp) {
888 TrafficSelector selector = DefaultTrafficSelector.builder()
889 .matchEthType(Ethernet.TYPE_IPV4)
890 .matchIPDst(dstIp.toIpPrefix())
891 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800892
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800893 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
894 .setEthDst(dstMac)
895 .setOutput(inPort)
896 .build();
897
898 FlowRule flowRule = DefaultFlowRule.builder()
899 .fromApp(appId)
900 .withSelector(selector)
901 .withTreatment(treatment)
902 .withPriority(DEFAULT_PRIORITY)
903 .forDevice(deviceId)
904 .forTable(TABLE_DST_IP)
905 .makePermanent()
906 .build();
907
908 processFlowRule(true, flowRule);
909
910 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
911 if (device.id().equals(deviceId)) {
912 continue;
913 }
914
915 ExtensionTreatment tunnelDst = getTunnelDst(device.id(), tunnelIp.getIp4Address());
916 if (tunnelDst == null) {
917 continue;
918 }
919
920 treatment = DefaultTrafficTreatment.builder()
921 .setEthDst(dstMac)
922 .setTunnelId(tunnelId)
923 .extension(tunnelDst, device.id())
924 .setOutput(getTunnelPort(device.id()))
925 .build();
926
927 flowRule = DefaultFlowRule.builder()
928 .fromApp(appId)
929 .withSelector(selector)
930 .withTreatment(treatment)
931 .withPriority(DEFAULT_PRIORITY)
932 .forDevice(device.id())
933 .forTable(TABLE_DST_IP)
934 .makePermanent()
935 .build();
936
937 processFlowRule(true, flowRule);
938 }
939 }
940
941 /**
942 * Populates flow rules for TUNNEL_ID table.
943 *
944 * @param deviceId device id
945 * @param inPort in port
946 * @param mac mac address
947 * @param tunnelId tunnel id
948 */
949 private void populateTunnelInRule(DeviceId deviceId, PortNumber inPort, MacAddress mac, long tunnelId) {
950 TrafficSelector selector = DefaultTrafficSelector.builder()
951 .matchTunnelId(tunnelId)
952 .matchEthDst(mac)
953 .build();
954
955 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
956 .setOutput(inPort)
957 .build();
958
959 FlowRule flowRule = DefaultFlowRule.builder()
960 .fromApp(appId)
961 .withSelector(selector)
962 .withTreatment(treatment)
963 .withPriority(DEFAULT_PRIORITY)
964 .forDevice(deviceId)
965 .forTable(TABLE_TUNNEL_IN)
966 .makePermanent()
967 .build();
968
969 processFlowRule(true, flowRule);
970 }
971
972 /**
973 * Installs or uninstall a given rule.
974 *
975 * @param install true to install, false to uninstall
976 * @param rule rule
977 */
978 private void processFlowRule(boolean install, FlowRule rule) {
979 FlowRuleOperations.Builder oBuilder = FlowRuleOperations.builder();
980 oBuilder = install ? oBuilder.add(rule) : oBuilder.remove(rule);
981
982 flowRuleService.apply(oBuilder.build(new FlowRuleOperationsContext() {
983 @Override
984 public void onError(FlowRuleOperations ops) {
985 log.error(String.format("Failed %s, %s", ops.toString(), rule.toString()));
986 }
987 }));
988 }
989
990 /**
991 * Returns tunnel port of the device.
992 *
993 * @param deviceId device id
994 * @return tunnel port number, or null if no tunnel port exists on a given device
995 */
996 private PortNumber getTunnelPort(DeviceId deviceId) {
Hyunsun Moon5a4346f2016-01-15 11:41:14 -0800997 Port port = deviceService.getPorts(deviceId).stream()
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800998 .filter(p -> p.annotations().value("portName").contains(tunnelType))
Hyunsun Moon5a4346f2016-01-15 11:41:14 -0800999 .findFirst().orElse(null);
1000
1001 return port == null ? null : port.number();
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001002 }
1003
1004 /**
Hyunsun Moon4a915152016-01-14 16:56:26 -08001005 * Returns physical port name of a given device.
1006 *
1007 * @param deviceId device id
1008 * @param phyPortName physical port name
1009 * @return physical port number, or null if no physical port exists
1010 */
1011 private PortNumber getPhyPort(DeviceId deviceId, String phyPortName) {
Hyunsun Moon5a4346f2016-01-15 11:41:14 -08001012 Port port = deviceService.getPorts(deviceId).stream()
Hyunsun Moon4a915152016-01-14 16:56:26 -08001013 .filter(p -> p.annotations().value("portName").contains(phyPortName) &&
1014 p.isEnabled())
Hyunsun Moon5a4346f2016-01-15 11:41:14 -08001015 .findFirst().orElse(null);
1016
1017 return port == null ? null : port.number();
Hyunsun Moon4a915152016-01-14 16:56:26 -08001018 }
1019
1020 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001021 * Returns the inport from a given flow rule if the rule contains the match of it.
1022 *
1023 * @param flowRule flow rule
1024 * @return port number, or null if the rule doesn't have inport match
1025 */
1026 private PortNumber getInPort(FlowRule flowRule) {
1027 Criterion criterion = flowRule.selector().getCriterion(IN_PORT);
1028 if (criterion != null && criterion instanceof PortCriterion) {
1029 PortCriterion port = (PortCriterion) criterion;
1030 return port.port();
1031 } else {
1032 return null;
1033 }
1034 }
1035
1036 /**
1037 * Returns the destination mac address from a given flow rule if the rule
1038 * contains the instruction of it.
1039 *
1040 * @param flowRule flow rule
1041 * @return mac address, or null if the rule doesn't have destination mac instruction
1042 */
1043 private MacAddress getDstMacFromTreatment(FlowRule flowRule) {
1044 Instruction instruction = flowRule.treatment().allInstructions().stream()
1045 .filter(inst -> inst instanceof ModEtherInstruction &&
1046 ((ModEtherInstruction) inst).subtype().equals(ETH_DST))
1047 .findFirst()
1048 .orElse(null);
1049
1050 if (instruction == null) {
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001051 return null;
1052 }
1053
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001054 return ((ModEtherInstruction) instruction).mac();
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001055 }
1056
1057 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001058 * Returns the destination mac address from a given flow rule if the rule
1059 * contains the match of it.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001060 *
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001061 * @param flowRule flow rule
1062 * @return mac address, or null if the rule doesn't have destination mac match
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001063 */
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001064 private MacAddress getDstMacFromSelector(FlowRule flowRule) {
1065 Criterion criterion = flowRule.selector().getCriterion(Criterion.Type.ETH_DST);
1066 if (criterion != null && criterion instanceof EthCriterion) {
1067 EthCriterion eth = (EthCriterion) criterion;
1068 return eth.mac();
1069 } else {
1070 return null;
1071 }
1072 }
1073
1074 /**
1075 * Returns the destination IP from a given flow rule if the rule contains
1076 * the match of it.
1077 *
1078 * @param flowRule flow rule
1079 * @return ip prefix, or null if the rule doesn't have ip match
1080 */
1081 private IpPrefix getDstIpFromSelector(FlowRule flowRule) {
1082 Criterion criterion = flowRule.selector().getCriterion(IPV4_DST);
1083 if (criterion != null && criterion instanceof IPCriterion) {
1084 IPCriterion ip = (IPCriterion) criterion;
1085 return ip.ip();
1086 } else {
1087 return null;
1088 }
1089 }
1090
1091 /**
1092 * Returns the source IP from a given flow rule if the rule contains
1093 * the match of it.
1094 *
1095 * @param flowRule flow rule
1096 * @return ip prefix, or null if the rule doesn't have ip match
1097 */
1098 private IpPrefix getSrcIpFromSelector(FlowRule flowRule) {
1099 Criterion criterion = flowRule.selector().getCriterion(IPV4_SRC);
1100 if (criterion != null && criterion instanceof IPCriterion) {
1101 IPCriterion ip = (IPCriterion) criterion;
1102 return ip.ip();
1103 } else {
1104 return null;
1105 }
1106 }
1107
1108 /**
1109 * Returns the group ID from a given flow rule if the rule contains the
1110 * treatment of it.
1111 *
1112 * @param flowRule flow rule
1113 * @return group id, or null if the rule doesn't have group instruction
1114 */
1115 private GroupId getGroupIdFromTreatment(FlowRule flowRule) {
1116 Instruction instruction = flowRule.treatment().allInstructions().stream()
1117 .filter(inst -> inst instanceof Instructions.GroupInstruction)
1118 .findFirst()
1119 .orElse(null);
1120
1121 if (instruction == null) {
1122 return null;
1123 }
1124
1125 return ((Instructions.GroupInstruction) instruction).groupId();
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001126 }
1127
1128 /**
Hyunsun Moond52bffc2016-01-29 18:57:05 -08001129 * Returns the output port number from a given flow rule.
1130 *
1131 * @param flowRule flow rule
1132 * @return port number, or null if the rule does not have output instruction
1133 */
1134 private PortNumber getOutputFromTreatment(FlowRule flowRule) {
1135 Instruction instruction = flowRule.treatment().allInstructions().stream()
1136 .filter(inst -> inst instanceof Instructions.OutputInstruction)
1137 .findFirst()
1138 .orElse(null);
1139
1140 if (instruction == null) {
1141 return null;
1142 }
1143
1144 return ((Instructions.OutputInstruction) instruction).port();
1145 }
1146
1147 /**
Hyunsun Moon4a915152016-01-14 16:56:26 -08001148 * Creates a new group for a given service.
1149 *
1150 * @param deviceId device id to create a group
1151 * @param service cord service
1152 * @return group id, or null if it fails to create
1153 */
1154 private GroupId createServiceGroup(DeviceId deviceId, CordService service) {
1155 checkNotNull(service);
1156
1157 GroupKey groupKey = getGroupKey(service.id());
1158 Group group = groupService.getGroup(deviceId, groupKey);
1159 GroupId groupId = getGroupId(service.id(), deviceId);
1160
1161 if (group != null) {
1162 log.debug("Group {} is already exist in {}", service.id(), deviceId);
1163 return groupId;
1164 }
1165
1166 GroupBuckets buckets = getServiceGroupBuckets(deviceId, service.segmentationId(), service.hosts());
1167 GroupDescription groupDescription = new DefaultGroupDescription(
1168 deviceId,
1169 GroupDescription.Type.SELECT,
1170 buckets,
1171 groupKey,
1172 groupId.id(),
1173 appId);
1174
1175 groupService.addGroup(groupDescription);
1176
1177 return groupId;
1178 }
1179
1180 /**
1181 * Returns group buckets for a given device.
1182 *
1183 * @param deviceId device id
1184 * @param tunnelId tunnel id
1185 * @param hosts list of host
1186 * @return group buckets
1187 */
1188 private GroupBuckets getServiceGroupBuckets(DeviceId deviceId, long tunnelId, Map<Host, IpAddress> hosts) {
1189 List<GroupBucket> buckets = Lists.newArrayList();
1190
1191 for (Map.Entry<Host, IpAddress> entry : hosts.entrySet()) {
1192 Host host = entry.getKey();
1193 Ip4Address remoteIp = entry.getValue().getIp4Address();
1194 DeviceId hostDevice = host.location().deviceId();
1195
1196 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
1197 .builder()
1198 .setEthDst(host.mac());
1199
1200 if (deviceId.equals(hostDevice)) {
1201 tBuilder.setOutput(host.location().port());
1202 } else {
1203 ExtensionTreatment tunnelDst = getTunnelDst(deviceId, remoteIp);
1204 if (tunnelDst == null) {
1205 continue;
1206 }
1207
1208 tBuilder.extension(tunnelDst, deviceId)
1209 .setTunnelId(tunnelId)
1210 .setOutput(getTunnelPort(hostDevice));
1211 }
1212
1213 buckets.add(DefaultGroupBucket.createSelectGroupBucket(tBuilder.build()));
1214 }
1215
1216 return new GroupBuckets(buckets);
1217 }
1218
1219 /**
1220 * Returns globally unique group ID.
1221 *
1222 * @param serviceId service id
1223 * @param deviceId device id
1224 * @return group id
1225 */
1226 private GroupId getGroupId(CordServiceId serviceId, DeviceId deviceId) {
1227 return new DefaultGroupId(Objects.hash(serviceId, deviceId));
1228 }
1229
1230 /**
1231 * Returns group key of a service.
1232 *
1233 * @param serviceId service id
1234 * @return group key
1235 */
1236 private GroupKey getGroupKey(CordServiceId serviceId) {
1237 return new DefaultGroupKey(serviceId.id().getBytes());
1238 }
1239
1240 /**
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001241 * Returns extension instruction to set tunnel destination.
1242 *
1243 * @param deviceId device id
1244 * @param remoteIp tunnel destination address
1245 * @return extension treatment or null if it fails to get instruction
1246 */
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001247 private ExtensionTreatment getTunnelDst(DeviceId deviceId, Ip4Address remoteIp) {
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001248 try {
1249 Driver driver = driverService.getDriver(deviceId);
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001250 DefaultDriverData driverData = new DefaultDriverData(driver, deviceId);
1251 DriverHandler handler = new DefaultDriverHandler(driverData);
1252 ExtensionTreatmentResolver resolver = handler.behaviour(ExtensionTreatmentResolver.class);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001253
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001254 ExtensionTreatment treatment =
1255 resolver.getExtensionInstruction(NICIRA_SET_TUNNEL_DST.type());
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001256 treatment.setPropertyValue("tunnelDst", remoteIp);
1257
1258 return treatment;
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001259 } catch (ItemNotFoundException | UnsupportedOperationException |
1260 ExtensionPropertyException e) {
1261 log.error("Failed to get extension instruction {}", deviceId);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001262 return null;
1263 }
1264 }
1265}
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001266