blob: 7fb85740d77c92587e0fb4f950efc6e6974a0491 [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()));
Hyunsun Moon81ab23b2016-02-01 23:00:56 -0800199 populateServiceIsolationRule(Ip4Prefix.valueOf(subnet.cidr()));
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800200 populateDstIpRule(deviceId, inPort, dstMac, hostIp, tunnelId, tunnelIp);
201 populateTunnelInRule(deviceId, inPort, dstMac, tunnelId);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800202 }
203
204 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800205 * Removes basic rules related to a given flow information.
206 *
207 * @param host host to be removed
208 */
209 public void removeBasicConnectionRules(Host host) {
210 checkNotNull(host);
211
212 DeviceId deviceId = host.location().deviceId();
213 MacAddress mac = host.mac();
214 PortNumber port = host.location().port();
215 IpAddress ip = host.ipAddresses().stream().findFirst().orElse(null);
216
217 if (!mastershipService.isLocalMaster(deviceId)) {
218 return;
219 }
220
221 for (FlowRule flowRule : flowRuleService.getFlowRulesById(appId)) {
222 if (flowRule.deviceId().equals(deviceId)) {
223 PortNumber inPort = getInPort(flowRule);
224 if (inPort != null && inPort.equals(port)) {
225 processFlowRule(false, flowRule);
226 continue;
227 }
228 }
229
230 MacAddress dstMac = getDstMacFromTreatment(flowRule);
231 if (dstMac != null && dstMac.equals(mac)) {
232 processFlowRule(false, flowRule);
233 continue;
234 }
235
236 dstMac = getDstMacFromSelector(flowRule);
237 if (dstMac != null && dstMac.equals(mac)) {
238 processFlowRule(false, flowRule);
239 continue;
240 }
241
242 IpPrefix dstIp = getDstIpFromSelector(flowRule);
243 if (dstIp != null && dstIp.equals(ip.toIpPrefix())) {
244 processFlowRule(false, flowRule);
245 }
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800246 }
247
248 // TODO uninstall same network access rule in access table if no vm exists in the network
249 }
250
251 /**
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800252 * Populates service dependency rules.
253 *
254 * @param tService tenant cord service
255 * @param pService provider cord service
256 */
257 public void populateServiceDependencyRules(CordService tService, CordService pService) {
258 checkNotNull(tService);
259 checkNotNull(pService);
260
261 Ip4Prefix srcRange = tService.serviceIpRange().getIp4Prefix();
262 Ip4Prefix dstRange = pService.serviceIpRange().getIp4Prefix();
263 Ip4Address serviceIp = pService.serviceIp().getIp4Address();
264
265 Map<DeviceId, GroupId> outGroups = Maps.newHashMap();
266 Map<DeviceId, Set<PortNumber>> inPorts = Maps.newHashMap();
267
268 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
269 GroupId groupId = createServiceGroup(device.id(), pService);
270 outGroups.put(device.id(), groupId);
271
272 Set<PortNumber> vms = tService.hosts().keySet()
273 .stream()
274 .filter(host -> host.location().deviceId().equals(device.id()))
275 .map(host -> host.location().port())
276 .collect(Collectors.toSet());
277 inPorts.put(device.id(), vms);
278 }
279
280 populateIndirectAccessRule(srcRange, serviceIp, outGroups);
281 populateDirectAccessRule(srcRange, dstRange);
282 populateInServiceRule(inPorts, outGroups);
283 }
284
285 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800286 * Removes service dependency rules.
287 *
288 * @param tService tenant cord service
289 * @param pService provider cord service
290 */
291 public void removeServiceDependencyRules(CordService tService, CordService pService) {
292 checkNotNull(tService);
293 checkNotNull(pService);
294
295 Ip4Prefix srcRange = tService.serviceIpRange().getIp4Prefix();
296 Ip4Prefix dstRange = pService.serviceIpRange().getIp4Prefix();
297 IpPrefix serviceIp = pService.serviceIp().toIpPrefix();
298
299 Map<DeviceId, GroupId> outGroups = Maps.newHashMap();
300 GroupKey groupKey = new DefaultGroupKey(pService.id().id().getBytes());
301
302 deviceService.getAvailableDevices(SWITCH).forEach(device -> {
303 Group group = groupService.getGroup(device.id(), groupKey);
304 if (group != null) {
305 outGroups.put(device.id(), group.id());
306 }
307 });
308
309 for (FlowRule flowRule : flowRuleService.getFlowRulesById(appId)) {
310 IpPrefix dstIp = getDstIpFromSelector(flowRule);
311 IpPrefix srcIp = getSrcIpFromSelector(flowRule);
312
313 if (dstIp != null && dstIp.equals(serviceIp)) {
314 processFlowRule(false, flowRule);
315 continue;
316 }
317
318 if (dstIp != null && srcIp != null) {
319 if (dstIp.equals(dstRange) && srcIp.equals(srcRange)) {
320 processFlowRule(false, flowRule);
321 continue;
322 }
323
324 if (dstIp.equals(srcRange) && srcIp.equals(dstRange)) {
325 processFlowRule(false, flowRule);
326 continue;
327 }
328 }
329
330 GroupId groupId = getGroupIdFromTreatment(flowRule);
331 if (groupId != null && groupId.equals(outGroups.get(flowRule.deviceId()))) {
332 processFlowRule(false, flowRule);
333 }
334 }
335
336 // TODO remove the group if it is not in use
337 }
338
339 /**
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800340 * Updates group buckets for a given service to all devices.
341 *
342 * @param service cord service
343 */
344 public void updateServiceGroup(CordService service) {
345 checkNotNull(service);
346
347 GroupKey groupKey = getGroupKey(service.id());
348
349 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
350 DeviceId deviceId = device.id();
351 if (!mastershipService.isLocalMaster(deviceId)) {
352 continue;
353 }
354
355 Group group = groupService.getGroup(deviceId, groupKey);
356 if (group == null) {
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800357 log.trace("No group exists for service {} in {}, do nothing.", service.id(), deviceId);
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800358 continue;
359 }
360
361 List<GroupBucket> oldBuckets = group.buckets().buckets();
362 List<GroupBucket> newBuckets = getServiceGroupBuckets(
363 deviceId, service.segmentationId(), service.hosts()).buckets();
364
365 if (oldBuckets.equals(newBuckets)) {
366 continue;
367 }
368
369 List<GroupBucket> bucketsToRemove = new ArrayList<>(oldBuckets);
370 bucketsToRemove.removeAll(newBuckets);
371 if (!bucketsToRemove.isEmpty()) {
372 groupService.removeBucketsFromGroup(
373 deviceId,
374 groupKey,
375 new GroupBuckets(bucketsToRemove),
376 groupKey, appId);
377 }
378
379 List<GroupBucket> bucketsToAdd = new ArrayList<>(newBuckets);
380 bucketsToAdd.removeAll(oldBuckets);
381 if (!bucketsToAdd.isEmpty()) {
382 groupService.addBucketsToGroup(
383 deviceId,
384 groupKey,
385 new GroupBuckets(bucketsToAdd),
386 groupKey, appId);
387 }
388 }
389 }
390
391 /**
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800392 * Populates flow rules for management network access.
393 *
394 * @param host host which has management network interface
395 * @param mService management network service
396 */
397 public void populateManagementNetworkRules(Host host, CordService mService) {
398 checkNotNull(mService);
399
400 DeviceId deviceId = host.location().deviceId();
401 IpAddress hostIp = host.ipAddresses().stream().findFirst().get();
402
403 TrafficSelector selector = DefaultTrafficSelector.builder()
404 .matchEthType(Ethernet.TYPE_ARP)
405 .matchArpTpa(mService.serviceIp().getIp4Address())
406 .build();
407
408 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
409 .setOutput(PortNumber.LOCAL)
410 .build();
411
412 FlowRule flowRule = DefaultFlowRule.builder()
413 .fromApp(appId)
414 .withSelector(selector)
415 .withTreatment(treatment)
416 .withPriority(MANAGEMENT_PRIORITY)
417 .forDevice(deviceId)
418 .forTable(TABLE_FIRST)
419 .makePermanent()
420 .build();
421
422 processFlowRule(true, flowRule);
423
424 selector = DefaultTrafficSelector.builder()
425 .matchInPort(PortNumber.LOCAL)
426 .matchEthType(Ethernet.TYPE_ARP)
427 .matchArpTpa(hostIp.getIp4Address())
428 .build();
429
430 treatment = DefaultTrafficTreatment.builder()
431 .setOutput(host.location().port())
432 .build();
433
434 flowRule = DefaultFlowRule.builder()
435 .fromApp(appId)
436 .withSelector(selector)
437 .withTreatment(treatment)
438 .withPriority(MANAGEMENT_PRIORITY)
439 .forDevice(deviceId)
440 .forTable(TABLE_FIRST)
441 .makePermanent()
442 .build();
443
444 processFlowRule(true, flowRule);
445
446 selector = DefaultTrafficSelector.builder()
447 .matchInPort(PortNumber.LOCAL)
448 .matchEthType(Ethernet.TYPE_IPV4)
449 .matchIPDst(mService.serviceIpRange())
450 .build();
451
452 treatment = DefaultTrafficTreatment.builder()
453 .transition(TABLE_DST_IP)
454 .build();
455
456 flowRule = DefaultFlowRule.builder()
457 .fromApp(appId)
458 .withSelector(selector)
459 .withTreatment(treatment)
460 .withPriority(MANAGEMENT_PRIORITY)
461 .forDevice(deviceId)
462 .forTable(TABLE_FIRST)
463 .makePermanent()
464 .build();
465
466 processFlowRule(true, flowRule);
467
468 selector = DefaultTrafficSelector.builder()
469 .matchEthType(Ethernet.TYPE_IPV4)
470 .matchIPDst(mService.serviceIp().toIpPrefix())
471 .build();
472
473 treatment = DefaultTrafficTreatment.builder()
474 .setOutput(PortNumber.LOCAL)
475 .build();
476
477 flowRule = DefaultFlowRule.builder()
478 .fromApp(appId)
479 .withSelector(selector)
480 .withTreatment(treatment)
481 .withPriority(MANAGEMENT_PRIORITY)
482 .forDevice(deviceId)
483 .forTable(TABLE_ACCESS_TYPE)
484 .makePermanent()
485 .build();
486
487 processFlowRule(true, flowRule);
488 }
489
490 /**
491 * Removes management network access rules.
492 *
493 * @param host host to be removed
494 * @param mService service for management network
495 */
496 public void removeManagementNetworkRules(Host host, CordService mService) {
497 checkNotNull(mService);
498
499 for (FlowRule flowRule : flowRuleService.getFlowRulesById(appId)) {
500 if (flowRule.deviceId().equals(host.location().deviceId())) {
501 PortNumber port = getOutputFromTreatment(flowRule);
502 if (port != null && port.equals(host.location().port())) {
503 processFlowRule(false, flowRule);
504 }
505 }
506
507 // TODO remove the other rules if mgmt network is not in use
508 }
509 }
510
511 /**
Hyunsun Moon4a915152016-01-14 16:56:26 -0800512 * Populates default rules on the first table.
513 * The rules are for shuttling vxlan-encapped packets and supporting physical
514 * network connectivity.
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800515 *
516 * @param deviceId device id
Hyunsun Moon4a915152016-01-14 16:56:26 -0800517 * @param phyPort physical port number
518 * @param localIp local data plane ip address
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800519 */
Hyunsun Moon4a915152016-01-14 16:56:26 -0800520 private void processFirstTable(DeviceId deviceId, PortNumber phyPort, IpAddress localIp) {
521 // take vxlan packet out onto the physical port
522 TrafficSelector selector = DefaultTrafficSelector.builder()
523 .matchInPort(PortNumber.LOCAL)
524 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800525
Hyunsun Moon4a915152016-01-14 16:56:26 -0800526 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
527 .setOutput(phyPort)
528 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800529
Hyunsun Moon4a915152016-01-14 16:56:26 -0800530 FlowRule flowRule = DefaultFlowRule.builder()
531 .fromApp(appId)
532 .withSelector(selector)
533 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800534 .withPriority(HIGH_PRIORITY)
Hyunsun Moon4a915152016-01-14 16:56:26 -0800535 .forDevice(deviceId)
536 .forTable(TABLE_FIRST)
537 .makePermanent()
538 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800539
Hyunsun Moon4a915152016-01-14 16:56:26 -0800540 processFlowRule(true, flowRule);
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800541
Hyunsun Moon4a915152016-01-14 16:56:26 -0800542 // take a vxlan encap'd packet through the Linux stack
543 selector = DefaultTrafficSelector.builder()
544 .matchInPort(phyPort)
545 .matchEthType(Ethernet.TYPE_IPV4)
546 .matchIPProtocol(IPv4.PROTOCOL_UDP)
547 .matchUdpDst(TpPort.tpPort(VXLAN_UDP_PORT))
548 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800549
Hyunsun Moon4a915152016-01-14 16:56:26 -0800550 treatment = DefaultTrafficTreatment.builder()
551 .setOutput(PortNumber.LOCAL)
552 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800553
Hyunsun Moon4a915152016-01-14 16:56:26 -0800554 flowRule = DefaultFlowRule.builder()
555 .fromApp(appId)
556 .withSelector(selector)
557 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800558 .withPriority(HIGH_PRIORITY)
Hyunsun Moon4a915152016-01-14 16:56:26 -0800559 .forDevice(deviceId)
560 .forTable(TABLE_FIRST)
561 .makePermanent()
562 .build();
563
564 processFlowRule(true, flowRule);
565
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800566 // take a packet to the local ip through Linux stack
567 selector = DefaultTrafficSelector.builder()
568 .matchInPort(phyPort)
569 .matchEthType(Ethernet.TYPE_IPV4)
570 .matchIPDst(localIp.toIpPrefix())
571 .build();
572
573 treatment = DefaultTrafficTreatment.builder()
574 .setOutput(PortNumber.LOCAL)
575 .build();
576
577 flowRule = DefaultFlowRule.builder()
578 .fromApp(appId)
579 .withSelector(selector)
580 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800581 .withPriority(HIGH_PRIORITY)
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800582 .forDevice(deviceId)
583 .forTable(TABLE_FIRST)
584 .makePermanent()
585 .build();
586
587 processFlowRule(true, flowRule);
588
589 // take an arp packet from physical through Linux stack
590 selector = DefaultTrafficSelector.builder()
591 .matchInPort(phyPort)
592 .matchEthType(Ethernet.TYPE_ARP)
593 .build();
594
595 treatment = DefaultTrafficTreatment.builder()
596 .setOutput(PortNumber.LOCAL)
597 .build();
598
599 flowRule = DefaultFlowRule.builder()
600 .fromApp(appId)
601 .withSelector(selector)
602 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800603 .withPriority(HIGH_PRIORITY)
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800604 .forDevice(deviceId)
605 .forTable(TABLE_FIRST)
606 .makePermanent()
607 .build();
608
609 processFlowRule(true, flowRule);
610
Hyunsun Moon4a915152016-01-14 16:56:26 -0800611 // take all else to the next table
612 selector = DefaultTrafficSelector.builder()
613 .build();
614
615 treatment = DefaultTrafficTreatment.builder()
616 .transition(TABLE_IN_PORT)
617 .build();
618
619 flowRule = DefaultFlowRule.builder()
620 .fromApp(appId)
621 .withSelector(selector)
622 .withTreatment(treatment)
623 .withPriority(LOWEST_PRIORITY)
624 .forDevice(deviceId)
625 .forTable(TABLE_FIRST)
626 .makePermanent()
627 .build();
628
629 processFlowRule(true, flowRule);
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800630 }
631
632 /**
Hyunsun Moon4a915152016-01-14 16:56:26 -0800633 * Forward table miss packets in ACCESS_TYPE table to physical port.
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800634 *
635 * @param deviceId device id
Hyunsun Moon4a915152016-01-14 16:56:26 -0800636 * @param phyPort physical port number
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800637 */
Hyunsun Moon4a915152016-01-14 16:56:26 -0800638 private void processAccessTypeTable(DeviceId deviceId, PortNumber phyPort) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800639 TrafficSelector selector = DefaultTrafficSelector.builder()
640 .build();
641
642 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Hyunsun Moon4a915152016-01-14 16:56:26 -0800643 .setOutput(phyPort)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800644 .build();
645
646 FlowRule flowRule = DefaultFlowRule.builder()
647 .fromApp(appId)
648 .withSelector(selector)
649 .withTreatment(treatment)
650 .withPriority(LOWEST_PRIORITY)
651 .forDevice(deviceId)
652 .forTable(TABLE_ACCESS_TYPE)
653 .makePermanent()
654 .build();
655
656 processFlowRule(true, flowRule);
657 }
658
659 /**
Hyunsun Moon4a915152016-01-14 16:56:26 -0800660 * Populates default rules for IN_PORT table.
661 * All packets from tunnel port are forwarded to TUNNEL_ID table and all packets
662 * from physical port to ACCESS_TYPE table.
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800663 *
664 * @param deviceId device id to install the rules
Hyunsun Moon4a915152016-01-14 16:56:26 -0800665 * @param tunnelPort tunnel port number
666 * @param phyPort physical port number
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800667 */
Hyunsun Moon4a915152016-01-14 16:56:26 -0800668 private void processInPortTable(DeviceId deviceId, PortNumber tunnelPort, PortNumber phyPort) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800669 checkNotNull(tunnelPort);
670
671 TrafficSelector selector = DefaultTrafficSelector.builder()
672 .matchInPort(tunnelPort)
673 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800674
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800675 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
676 .transition(TABLE_TUNNEL_IN)
677 .build();
678
679 FlowRule flowRule = DefaultFlowRule.builder()
680 .fromApp(appId)
681 .withSelector(selector)
682 .withTreatment(treatment)
683 .withPriority(DEFAULT_PRIORITY)
684 .forDevice(deviceId)
685 .forTable(TABLE_IN_PORT)
686 .makePermanent()
687 .build();
688
689 processFlowRule(true, flowRule);
Hyunsun Moon4a915152016-01-14 16:56:26 -0800690
691 selector = DefaultTrafficSelector.builder()
692 .matchInPort(phyPort)
693 .build();
694
695 treatment = DefaultTrafficTreatment.builder()
696 .transition(TABLE_DST_IP)
697 .build();
698
699 flowRule = DefaultFlowRule.builder()
700 .fromApp(appId)
701 .withSelector(selector)
702 .withTreatment(treatment)
703 .withPriority(DEFAULT_PRIORITY)
704 .forDevice(deviceId)
705 .forTable(TABLE_IN_PORT)
706 .makePermanent()
707 .build();
708
709 processFlowRule(true, flowRule);
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800710 }
711
712 /**
713 * Populates rules for local in port in IN_PORT table.
714 * Flows from a given in port, whose source IP is service IP transition
715 * to DST_TYPE table. Other flows transition to IN_SERVICE table.
716 *
717 * @param deviceId device id to install the rules
718 * @param inPort in port
719 * @param srcIp source ip
720 */
721 private void populateLocalInPortRule(DeviceId deviceId, PortNumber inPort, IpAddress srcIp) {
722 TrafficSelector selector = DefaultTrafficSelector.builder()
723 .matchInPort(inPort)
724 .matchEthType(Ethernet.TYPE_IPV4)
725 .matchIPSrc(srcIp.toIpPrefix())
726 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800727
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800728 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
729 .transition(TABLE_ACCESS_TYPE)
730 .build();
731
732
733 FlowRule flowRule = DefaultFlowRule.builder()
734 .fromApp(appId)
735 .withSelector(selector)
736 .withTreatment(treatment)
737 .withPriority(DEFAULT_PRIORITY)
738 .forDevice(deviceId)
739 .forTable(TABLE_IN_PORT)
740 .makePermanent()
741 .build();
742
743 processFlowRule(true, flowRule);
744
745 selector = DefaultTrafficSelector.builder()
746 .matchInPort(inPort)
747 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800748
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800749 treatment = DefaultTrafficTreatment.builder()
750 .transition(TABLE_IN_SERVICE)
751 .build();
752
753 flowRule = DefaultFlowRule.builder()
754 .fromApp(appId)
755 .withSelector(selector)
756 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800757 .withPriority(LOW_PRIORITY)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800758 .forDevice(deviceId)
759 .forTable(TABLE_IN_PORT)
760 .makePermanent()
761 .build();
762
763 processFlowRule(true, flowRule);
764 }
765
766 /**
767 * Populates direct VM access rules for ACCESS_TYPE table.
768 * These rules are installed to all devices.
769 *
770 * @param srcRange source ip range
771 * @param dstRange destination ip range
772 */
773 private void populateDirectAccessRule(Ip4Prefix srcRange, Ip4Prefix dstRange) {
774 TrafficSelector selector = DefaultTrafficSelector.builder()
775 .matchEthType(Ethernet.TYPE_IPV4)
776 .matchIPSrc(srcRange)
777 .matchIPDst(dstRange)
778 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800779
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800780 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
781 .transition(TABLE_DST_IP)
782 .build();
783
784 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
785 FlowRule flowRuleDirect = DefaultFlowRule.builder()
786 .fromApp(appId)
787 .withSelector(selector)
788 .withTreatment(treatment)
Hyunsun Moon81ab23b2016-02-01 23:00:56 -0800789 .withPriority(DEFAULT_PRIORITY)
790 .forDevice(device.id())
791 .forTable(TABLE_ACCESS_TYPE)
792 .makePermanent()
793 .build();
794
795 processFlowRule(true, flowRuleDirect);
796 }
797 }
798
799 /**
800 * Populates drop rules that does not match any direct access rules but has
801 * destination to a different service network in ACCESS_TYPE table.
802 *
803 * @param dstRange destination ip range
804 */
805 private void populateServiceIsolationRule(Ip4Prefix dstRange) {
806 TrafficSelector selector = DefaultTrafficSelector.builder()
807 .matchEthType(Ethernet.TYPE_IPV4)
808 .matchIPDst(dstRange)
809 .build();
810
811 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
812 .drop()
813 .build();
814
815 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
816 FlowRule flowRuleDirect = DefaultFlowRule.builder()
817 .fromApp(appId)
818 .withSelector(selector)
819 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800820 .withPriority(LOW_PRIORITY)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800821 .forDevice(device.id())
822 .forTable(TABLE_ACCESS_TYPE)
823 .makePermanent()
824 .build();
825
826 processFlowRule(true, flowRuleDirect);
827 }
828 }
829
830 /**
831 * Populates indirect service access rules for ACCESS_TYPE table.
832 * These rules are installed to all devices.
833 *
834 * @param srcRange source range
835 * @param serviceIp service ip
836 * @param outGroups list of output group
837 */
838 private void populateIndirectAccessRule(Ip4Prefix srcRange, Ip4Address serviceIp,
839 Map<DeviceId, GroupId> outGroups) {
840 TrafficSelector selector = DefaultTrafficSelector.builder()
841 .matchEthType(Ethernet.TYPE_IPV4)
842 .matchIPSrc(srcRange)
843 .matchIPDst(serviceIp.toIpPrefix())
844 .build();
845
846 for (Map.Entry<DeviceId, GroupId> outGroup : outGroups.entrySet()) {
847 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
848 .group(outGroup.getValue())
849 .build();
850
851 FlowRule flowRule = DefaultFlowRule.builder()
852 .fromApp(appId)
853 .withSelector(selector)
854 .withTreatment(treatment)
Hyunsun Moon81ab23b2016-02-01 23:00:56 -0800855 .withPriority(HIGH_PRIORITY)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800856 .forDevice(outGroup.getKey())
857 .forTable(TABLE_ACCESS_TYPE)
858 .makePermanent()
859 .build();
860
861 processFlowRule(true, flowRule);
862 }
863 }
864
865 /**
866 * Populates flow rules for IN_SERVICE table.
867 *
868 * @param inPorts list of inports related to the service for each device
869 * @param outGroups set of output groups
870 */
871 private void populateInServiceRule(Map<DeviceId, Set<PortNumber>> inPorts, Map<DeviceId, GroupId> outGroups) {
872 checkNotNull(inPorts);
873 checkNotNull(outGroups);
874
875 for (Map.Entry<DeviceId, Set<PortNumber>> entry : inPorts.entrySet()) {
876 Set<PortNumber> ports = entry.getValue();
877 DeviceId deviceId = entry.getKey();
878
879 GroupId groupId = outGroups.get(deviceId);
880 if (groupId == null) {
881 continue;
882 }
883
884 ports.stream().forEach(port -> {
885 TrafficSelector selector = DefaultTrafficSelector.builder()
886 .matchInPort(port)
887 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800888
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800889 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
890 .group(groupId)
891 .build();
892
893 FlowRule flowRule = DefaultFlowRule.builder()
894 .fromApp(appId)
895 .withSelector(selector)
896 .withTreatment(treatment)
897 .withPriority(DEFAULT_PRIORITY)
898 .forDevice(deviceId)
899 .forTable(TABLE_IN_SERVICE)
900 .makePermanent()
901 .build();
902
903 processFlowRule(true, flowRule);
904 });
905 }
906 }
907
908 /**
909 * Populates flow rules for DST_IP table.
910 *
911 * @param deviceId device id
912 * @param inPort in port
913 * @param dstMac mac address
914 * @param dstIp destination ip
915 * @param tunnelId tunnel id
916 * @param tunnelIp tunnel remote ip
917 */
918 private void populateDstIpRule(DeviceId deviceId, PortNumber inPort, MacAddress dstMac,
919 IpAddress dstIp, long tunnelId, IpAddress tunnelIp) {
920 TrafficSelector selector = DefaultTrafficSelector.builder()
921 .matchEthType(Ethernet.TYPE_IPV4)
922 .matchIPDst(dstIp.toIpPrefix())
923 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800924
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800925 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
926 .setEthDst(dstMac)
927 .setOutput(inPort)
928 .build();
929
930 FlowRule flowRule = DefaultFlowRule.builder()
931 .fromApp(appId)
932 .withSelector(selector)
933 .withTreatment(treatment)
934 .withPriority(DEFAULT_PRIORITY)
935 .forDevice(deviceId)
936 .forTable(TABLE_DST_IP)
937 .makePermanent()
938 .build();
939
940 processFlowRule(true, flowRule);
941
942 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
943 if (device.id().equals(deviceId)) {
944 continue;
945 }
946
947 ExtensionTreatment tunnelDst = getTunnelDst(device.id(), tunnelIp.getIp4Address());
948 if (tunnelDst == null) {
949 continue;
950 }
951
952 treatment = DefaultTrafficTreatment.builder()
953 .setEthDst(dstMac)
954 .setTunnelId(tunnelId)
955 .extension(tunnelDst, device.id())
956 .setOutput(getTunnelPort(device.id()))
957 .build();
958
959 flowRule = DefaultFlowRule.builder()
960 .fromApp(appId)
961 .withSelector(selector)
962 .withTreatment(treatment)
963 .withPriority(DEFAULT_PRIORITY)
964 .forDevice(device.id())
965 .forTable(TABLE_DST_IP)
966 .makePermanent()
967 .build();
968
969 processFlowRule(true, flowRule);
970 }
971 }
972
973 /**
974 * Populates flow rules for TUNNEL_ID table.
975 *
976 * @param deviceId device id
977 * @param inPort in port
978 * @param mac mac address
979 * @param tunnelId tunnel id
980 */
981 private void populateTunnelInRule(DeviceId deviceId, PortNumber inPort, MacAddress mac, long tunnelId) {
982 TrafficSelector selector = DefaultTrafficSelector.builder()
983 .matchTunnelId(tunnelId)
984 .matchEthDst(mac)
985 .build();
986
987 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
988 .setOutput(inPort)
989 .build();
990
991 FlowRule flowRule = DefaultFlowRule.builder()
992 .fromApp(appId)
993 .withSelector(selector)
994 .withTreatment(treatment)
995 .withPriority(DEFAULT_PRIORITY)
996 .forDevice(deviceId)
997 .forTable(TABLE_TUNNEL_IN)
998 .makePermanent()
999 .build();
1000
1001 processFlowRule(true, flowRule);
1002 }
1003
1004 /**
1005 * Installs or uninstall a given rule.
1006 *
1007 * @param install true to install, false to uninstall
1008 * @param rule rule
1009 */
1010 private void processFlowRule(boolean install, FlowRule rule) {
1011 FlowRuleOperations.Builder oBuilder = FlowRuleOperations.builder();
1012 oBuilder = install ? oBuilder.add(rule) : oBuilder.remove(rule);
1013
1014 flowRuleService.apply(oBuilder.build(new FlowRuleOperationsContext() {
1015 @Override
1016 public void onError(FlowRuleOperations ops) {
1017 log.error(String.format("Failed %s, %s", ops.toString(), rule.toString()));
1018 }
1019 }));
1020 }
1021
1022 /**
1023 * Returns tunnel port of the device.
1024 *
1025 * @param deviceId device id
1026 * @return tunnel port number, or null if no tunnel port exists on a given device
1027 */
1028 private PortNumber getTunnelPort(DeviceId deviceId) {
Hyunsun Moon5a4346f2016-01-15 11:41:14 -08001029 Port port = deviceService.getPorts(deviceId).stream()
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001030 .filter(p -> p.annotations().value("portName").contains(tunnelType))
Hyunsun Moon5a4346f2016-01-15 11:41:14 -08001031 .findFirst().orElse(null);
1032
1033 return port == null ? null : port.number();
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001034 }
1035
1036 /**
Hyunsun Moon4a915152016-01-14 16:56:26 -08001037 * Returns physical port name of a given device.
1038 *
1039 * @param deviceId device id
1040 * @param phyPortName physical port name
1041 * @return physical port number, or null if no physical port exists
1042 */
1043 private PortNumber getPhyPort(DeviceId deviceId, String phyPortName) {
Hyunsun Moon5a4346f2016-01-15 11:41:14 -08001044 Port port = deviceService.getPorts(deviceId).stream()
Hyunsun Moon4a915152016-01-14 16:56:26 -08001045 .filter(p -> p.annotations().value("portName").contains(phyPortName) &&
1046 p.isEnabled())
Hyunsun Moon5a4346f2016-01-15 11:41:14 -08001047 .findFirst().orElse(null);
1048
1049 return port == null ? null : port.number();
Hyunsun Moon4a915152016-01-14 16:56:26 -08001050 }
1051
1052 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001053 * Returns the inport from a given flow rule if the rule contains the match of it.
1054 *
1055 * @param flowRule flow rule
1056 * @return port number, or null if the rule doesn't have inport match
1057 */
1058 private PortNumber getInPort(FlowRule flowRule) {
1059 Criterion criterion = flowRule.selector().getCriterion(IN_PORT);
1060 if (criterion != null && criterion instanceof PortCriterion) {
1061 PortCriterion port = (PortCriterion) criterion;
1062 return port.port();
1063 } else {
1064 return null;
1065 }
1066 }
1067
1068 /**
1069 * Returns the destination mac address from a given flow rule if the rule
1070 * contains the instruction of it.
1071 *
1072 * @param flowRule flow rule
1073 * @return mac address, or null if the rule doesn't have destination mac instruction
1074 */
1075 private MacAddress getDstMacFromTreatment(FlowRule flowRule) {
1076 Instruction instruction = flowRule.treatment().allInstructions().stream()
1077 .filter(inst -> inst instanceof ModEtherInstruction &&
1078 ((ModEtherInstruction) inst).subtype().equals(ETH_DST))
1079 .findFirst()
1080 .orElse(null);
1081
1082 if (instruction == null) {
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001083 return null;
1084 }
1085
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001086 return ((ModEtherInstruction) instruction).mac();
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001087 }
1088
1089 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001090 * Returns the destination mac address from a given flow rule if the rule
1091 * contains the match of it.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001092 *
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001093 * @param flowRule flow rule
1094 * @return mac address, or null if the rule doesn't have destination mac match
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001095 */
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001096 private MacAddress getDstMacFromSelector(FlowRule flowRule) {
1097 Criterion criterion = flowRule.selector().getCriterion(Criterion.Type.ETH_DST);
1098 if (criterion != null && criterion instanceof EthCriterion) {
1099 EthCriterion eth = (EthCriterion) criterion;
1100 return eth.mac();
1101 } else {
1102 return null;
1103 }
1104 }
1105
1106 /**
1107 * Returns the destination IP from a given flow rule if the rule contains
1108 * the match of it.
1109 *
1110 * @param flowRule flow rule
1111 * @return ip prefix, or null if the rule doesn't have ip match
1112 */
1113 private IpPrefix getDstIpFromSelector(FlowRule flowRule) {
1114 Criterion criterion = flowRule.selector().getCriterion(IPV4_DST);
1115 if (criterion != null && criterion instanceof IPCriterion) {
1116 IPCriterion ip = (IPCriterion) criterion;
1117 return ip.ip();
1118 } else {
1119 return null;
1120 }
1121 }
1122
1123 /**
1124 * Returns the source IP from a given flow rule if the rule contains
1125 * the match of it.
1126 *
1127 * @param flowRule flow rule
1128 * @return ip prefix, or null if the rule doesn't have ip match
1129 */
1130 private IpPrefix getSrcIpFromSelector(FlowRule flowRule) {
1131 Criterion criterion = flowRule.selector().getCriterion(IPV4_SRC);
1132 if (criterion != null && criterion instanceof IPCriterion) {
1133 IPCriterion ip = (IPCriterion) criterion;
1134 return ip.ip();
1135 } else {
1136 return null;
1137 }
1138 }
1139
1140 /**
1141 * Returns the group ID from a given flow rule if the rule contains the
1142 * treatment of it.
1143 *
1144 * @param flowRule flow rule
1145 * @return group id, or null if the rule doesn't have group instruction
1146 */
1147 private GroupId getGroupIdFromTreatment(FlowRule flowRule) {
1148 Instruction instruction = flowRule.treatment().allInstructions().stream()
1149 .filter(inst -> inst instanceof Instructions.GroupInstruction)
1150 .findFirst()
1151 .orElse(null);
1152
1153 if (instruction == null) {
1154 return null;
1155 }
1156
1157 return ((Instructions.GroupInstruction) instruction).groupId();
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001158 }
1159
1160 /**
Hyunsun Moond52bffc2016-01-29 18:57:05 -08001161 * Returns the output port number from a given flow rule.
1162 *
1163 * @param flowRule flow rule
1164 * @return port number, or null if the rule does not have output instruction
1165 */
1166 private PortNumber getOutputFromTreatment(FlowRule flowRule) {
1167 Instruction instruction = flowRule.treatment().allInstructions().stream()
1168 .filter(inst -> inst instanceof Instructions.OutputInstruction)
1169 .findFirst()
1170 .orElse(null);
1171
1172 if (instruction == null) {
1173 return null;
1174 }
1175
1176 return ((Instructions.OutputInstruction) instruction).port();
1177 }
1178
1179 /**
Hyunsun Moon4a915152016-01-14 16:56:26 -08001180 * Creates a new group for a given service.
1181 *
1182 * @param deviceId device id to create a group
1183 * @param service cord service
1184 * @return group id, or null if it fails to create
1185 */
1186 private GroupId createServiceGroup(DeviceId deviceId, CordService service) {
1187 checkNotNull(service);
1188
1189 GroupKey groupKey = getGroupKey(service.id());
1190 Group group = groupService.getGroup(deviceId, groupKey);
1191 GroupId groupId = getGroupId(service.id(), deviceId);
1192
1193 if (group != null) {
1194 log.debug("Group {} is already exist in {}", service.id(), deviceId);
1195 return groupId;
1196 }
1197
1198 GroupBuckets buckets = getServiceGroupBuckets(deviceId, service.segmentationId(), service.hosts());
1199 GroupDescription groupDescription = new DefaultGroupDescription(
1200 deviceId,
1201 GroupDescription.Type.SELECT,
1202 buckets,
1203 groupKey,
1204 groupId.id(),
1205 appId);
1206
1207 groupService.addGroup(groupDescription);
1208
1209 return groupId;
1210 }
1211
1212 /**
1213 * Returns group buckets for a given device.
1214 *
1215 * @param deviceId device id
1216 * @param tunnelId tunnel id
1217 * @param hosts list of host
1218 * @return group buckets
1219 */
1220 private GroupBuckets getServiceGroupBuckets(DeviceId deviceId, long tunnelId, Map<Host, IpAddress> hosts) {
1221 List<GroupBucket> buckets = Lists.newArrayList();
1222
1223 for (Map.Entry<Host, IpAddress> entry : hosts.entrySet()) {
1224 Host host = entry.getKey();
1225 Ip4Address remoteIp = entry.getValue().getIp4Address();
1226 DeviceId hostDevice = host.location().deviceId();
1227
1228 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
1229 .builder()
1230 .setEthDst(host.mac());
1231
1232 if (deviceId.equals(hostDevice)) {
1233 tBuilder.setOutput(host.location().port());
1234 } else {
1235 ExtensionTreatment tunnelDst = getTunnelDst(deviceId, remoteIp);
1236 if (tunnelDst == null) {
1237 continue;
1238 }
1239
1240 tBuilder.extension(tunnelDst, deviceId)
1241 .setTunnelId(tunnelId)
1242 .setOutput(getTunnelPort(hostDevice));
1243 }
1244
1245 buckets.add(DefaultGroupBucket.createSelectGroupBucket(tBuilder.build()));
1246 }
1247
1248 return new GroupBuckets(buckets);
1249 }
1250
1251 /**
1252 * Returns globally unique group ID.
1253 *
1254 * @param serviceId service id
1255 * @param deviceId device id
1256 * @return group id
1257 */
1258 private GroupId getGroupId(CordServiceId serviceId, DeviceId deviceId) {
1259 return new DefaultGroupId(Objects.hash(serviceId, deviceId));
1260 }
1261
1262 /**
1263 * Returns group key of a service.
1264 *
1265 * @param serviceId service id
1266 * @return group key
1267 */
1268 private GroupKey getGroupKey(CordServiceId serviceId) {
1269 return new DefaultGroupKey(serviceId.id().getBytes());
1270 }
1271
1272 /**
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001273 * Returns extension instruction to set tunnel destination.
1274 *
1275 * @param deviceId device id
1276 * @param remoteIp tunnel destination address
1277 * @return extension treatment or null if it fails to get instruction
1278 */
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001279 private ExtensionTreatment getTunnelDst(DeviceId deviceId, Ip4Address remoteIp) {
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001280 try {
1281 Driver driver = driverService.getDriver(deviceId);
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001282 DefaultDriverData driverData = new DefaultDriverData(driver, deviceId);
1283 DriverHandler handler = new DefaultDriverHandler(driverData);
1284 ExtensionTreatmentResolver resolver = handler.behaviour(ExtensionTreatmentResolver.class);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001285
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001286 ExtensionTreatment treatment =
1287 resolver.getExtensionInstruction(NICIRA_SET_TUNNEL_DST.type());
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001288 treatment.setPropertyValue("tunnelDst", remoteIp);
1289
1290 return treatment;
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001291 } catch (ItemNotFoundException | UnsupportedOperationException |
1292 ExtensionPropertyException e) {
1293 log.error("Failed to get extension instruction {}", deviceId);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001294 return null;
1295 }
1296 }
1297}
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001298