blob: d1a0f247291919b224157eef9e743ccdb4711fbf [file] [log] [blame]
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.cordvtn;
17
Hyunsun Moonc71231d2015-12-16 20:53:23 -080018import com.google.common.collect.Lists;
19import com.google.common.collect.Maps;
20import org.onlab.packet.Ethernet;
Hyunsun Moon4a915152016-01-14 16:56:26 -080021import org.onlab.packet.IPv4;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080022import org.onlab.packet.Ip4Address;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080023import org.onlab.packet.Ip4Prefix;
24import org.onlab.packet.IpAddress;
25import org.onlab.packet.IpPrefix;
26import org.onlab.packet.MacAddress;
Hyunsun Moon4a915152016-01-14 16:56:26 -080027import org.onlab.packet.TpPort;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080028import org.onlab.util.ItemNotFoundException;
29import org.onosproject.core.ApplicationId;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080030import org.onosproject.core.DefaultGroupId;
31import org.onosproject.core.GroupId;
32import org.onosproject.mastership.MastershipService;
33import org.onosproject.net.Device;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080034import org.onosproject.net.DeviceId;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080035import org.onosproject.net.Host;
Hyunsun Moon5a4346f2016-01-15 11:41:14 -080036import org.onosproject.net.Port;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080037import org.onosproject.net.PortNumber;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080038import org.onosproject.net.behaviour.ExtensionTreatmentResolver;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080039import org.onosproject.net.device.DeviceService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080040import org.onosproject.net.driver.DefaultDriverData;
41import org.onosproject.net.driver.DefaultDriverHandler;
42import org.onosproject.net.driver.Driver;
43import org.onosproject.net.driver.DriverHandler;
44import org.onosproject.net.driver.DriverService;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080045import org.onosproject.net.flow.DefaultFlowRule;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080046import org.onosproject.net.flow.DefaultTrafficSelector;
47import org.onosproject.net.flow.DefaultTrafficTreatment;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080048import org.onosproject.net.flow.FlowRule;
49import org.onosproject.net.flow.FlowRuleOperations;
50import org.onosproject.net.flow.FlowRuleOperationsContext;
51import org.onosproject.net.flow.FlowRuleService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080052import org.onosproject.net.flow.TrafficSelector;
53import org.onosproject.net.flow.TrafficTreatment;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080054import org.onosproject.net.flow.criteria.Criterion;
55import org.onosproject.net.flow.criteria.EthCriterion;
56import org.onosproject.net.flow.criteria.IPCriterion;
57import org.onosproject.net.flow.criteria.PortCriterion;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080058import org.onosproject.net.flow.instructions.ExtensionPropertyException;
59import org.onosproject.net.flow.instructions.ExtensionTreatment;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080060import org.onosproject.net.flow.instructions.Instruction;
61import org.onosproject.net.flow.instructions.Instructions;
62import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
63import org.onosproject.net.group.DefaultGroupBucket;
64import org.onosproject.net.group.DefaultGroupDescription;
65import org.onosproject.net.group.DefaultGroupKey;
66import org.onosproject.net.group.Group;
67import org.onosproject.net.group.GroupBucket;
68import org.onosproject.net.group.GroupBuckets;
69import org.onosproject.net.group.GroupDescription;
70import org.onosproject.net.group.GroupKey;
71import org.onosproject.net.group.GroupService;
72import org.onosproject.openstackswitching.OpenstackNetwork;
73import org.onosproject.openstackswitching.OpenstackSubnet;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080074import org.slf4j.Logger;
75
Hyunsun Moon4161e6f2016-01-07 01:32:31 -080076import java.util.ArrayList;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080077import java.util.List;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080078import java.util.Map;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080079import java.util.Objects;
80import java.util.Set;
81import java.util.stream.Collectors;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080082
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080083import static com.google.common.base.Preconditions.checkNotNull;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080084import static org.onosproject.net.Device.Type.SWITCH;
85import static org.onosproject.net.flow.criteria.Criterion.Type.IN_PORT;
86import static org.onosproject.net.flow.criteria.Criterion.Type.IPV4_DST;
87import static org.onosproject.net.flow.criteria.Criterion.Type.IPV4_SRC;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080088import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080089import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.ETH_DST;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080090import static org.slf4j.LoggerFactory.getLogger;
91
92/**
Hyunsun Moonc71231d2015-12-16 20:53:23 -080093 * Populates rules for CORD VTN service.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080094 */
Hyunsun Moonc71231d2015-12-16 20:53:23 -080095public class CordVtnRuleInstaller {
96
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080097 protected final Logger log = getLogger(getClass());
98
Hyunsun Moon133fd792016-02-09 01:55:48 -080099 private static final String PORT_NAME = "portName";
Hyunsun Moon4a915152016-01-14 16:56:26 -0800100 private static final int TABLE_FIRST = 0;
101 private static final int TABLE_IN_PORT = 1;
102 private static final int TABLE_ACCESS_TYPE = 2;
103 private static final int TABLE_IN_SERVICE = 3;
104 private static final int TABLE_DST_IP = 4;
105 private static final int TABLE_TUNNEL_IN = 5;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800106
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800107 private static final int MANAGEMENT_PRIORITY = 55000;
108 private static final int HIGH_PRIORITY = 50000;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800109 private static final int DEFAULT_PRIORITY = 5000;
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800110 private static final int LOW_PRIORITY = 4000;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800111 private static final int LOWEST_PRIORITY = 0;
Hyunsun Moon4a915152016-01-14 16:56:26 -0800112
113 private static final int VXLAN_UDP_PORT = 4789;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800114
115 private final ApplicationId appId;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800116 private final FlowRuleService flowRuleService;
117 private final DeviceService deviceService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800118 private final DriverService driverService;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800119 private final GroupService groupService;
120 private final MastershipService mastershipService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800121 private final String tunnelType;
122
123 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800124 * Creates a new rule populator.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800125 *
126 * @param appId application id
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800127 * @param flowRuleService flow rule service
128 * @param deviceService device service
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800129 * @param driverService driver service
Jian Lidfba7392016-01-22 16:46:58 -0800130 * @param groupService group service
131 * @param mastershipService mastership service
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800132 * @param tunnelType tunnel type
133 */
134 public CordVtnRuleInstaller(ApplicationId appId,
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800135 FlowRuleService flowRuleService,
136 DeviceService deviceService,
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800137 DriverService driverService,
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800138 GroupService groupService,
139 MastershipService mastershipService,
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800140 String tunnelType) {
141 this.appId = appId;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800142 this.flowRuleService = flowRuleService;
143 this.deviceService = deviceService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800144 this.driverService = driverService;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800145 this.groupService = groupService;
146 this.mastershipService = mastershipService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800147 this.tunnelType = checkNotNull(tunnelType);
148 }
149
150 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800151 * Installs table miss rule to a give device.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800152 *
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800153 * @param deviceId device id to install the rules
Hyunsun Moon133fd792016-02-09 01:55:48 -0800154 * @param dpIntf data plane interface name
155 * @param dpIp data plane ip address
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800156 */
Hyunsun Moon133fd792016-02-09 01:55:48 -0800157 public void init(DeviceId deviceId, String dpIntf, IpAddress dpIp) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800158 // default is drop packets which can be accomplished without
159 // a table miss entry for all table.
Hyunsun Moon4a915152016-01-14 16:56:26 -0800160 PortNumber tunnelPort = getTunnelPort(deviceId);
Hyunsun Moon133fd792016-02-09 01:55:48 -0800161 PortNumber dpPort = getDpPort(deviceId, dpIntf);
Hyunsun Moon4a915152016-01-14 16:56:26 -0800162
Hyunsun Moon133fd792016-02-09 01:55:48 -0800163 processFirstTable(deviceId, dpPort, dpIp);
164 processInPortTable(deviceId, tunnelPort, dpPort);
165 processAccessTypeTable(deviceId, dpPort);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800166 }
167
168 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800169 * Populates basic rules that connect a VM to the other VMs in the system.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800170 *
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800171 * @param host host
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800172 * @param tunnelIp tunnel ip
173 * @param vNet openstack network
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800174 */
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800175 public void populateBasicConnectionRules(Host host, IpAddress tunnelIp, OpenstackNetwork vNet) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800176 checkNotNull(host);
177 checkNotNull(vNet);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800178
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800179 DeviceId deviceId = host.location().deviceId();
180 if (!mastershipService.isLocalMaster(deviceId)) {
181 return;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800182 }
183
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800184 PortNumber inPort = host.location().port();
185 MacAddress dstMac = host.mac();
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800186 IpAddress hostIp = host.ipAddresses().stream().findFirst().get();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800187 long tunnelId = Long.parseLong(vNet.segmentId());
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800188
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800189 OpenstackSubnet subnet = vNet.subnets().stream()
190 .findFirst()
191 .orElse(null);
192
193 if (subnet == null) {
194 log.error("Failed to get subnet for {}", host.id());
195 return;
196 }
197
198 populateLocalInPortRule(deviceId, inPort, hostIp);
199 populateDirectAccessRule(Ip4Prefix.valueOf(subnet.cidr()), Ip4Prefix.valueOf(subnet.cidr()));
Hyunsun Moon81ab23b2016-02-01 23:00:56 -0800200 populateServiceIsolationRule(Ip4Prefix.valueOf(subnet.cidr()));
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800201 populateDstIpRule(deviceId, inPort, dstMac, hostIp, tunnelId, tunnelIp);
202 populateTunnelInRule(deviceId, inPort, dstMac, tunnelId);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800203 }
204
205 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800206 * Removes basic rules related to a given flow information.
207 *
208 * @param host host to be removed
209 */
210 public void removeBasicConnectionRules(Host host) {
211 checkNotNull(host);
212
213 DeviceId deviceId = host.location().deviceId();
214 MacAddress mac = host.mac();
215 PortNumber port = host.location().port();
216 IpAddress ip = host.ipAddresses().stream().findFirst().orElse(null);
217
218 if (!mastershipService.isLocalMaster(deviceId)) {
219 return;
220 }
221
222 for (FlowRule flowRule : flowRuleService.getFlowRulesById(appId)) {
223 if (flowRule.deviceId().equals(deviceId)) {
224 PortNumber inPort = getInPort(flowRule);
225 if (inPort != null && inPort.equals(port)) {
226 processFlowRule(false, flowRule);
227 continue;
228 }
229 }
230
231 MacAddress dstMac = getDstMacFromTreatment(flowRule);
232 if (dstMac != null && dstMac.equals(mac)) {
233 processFlowRule(false, flowRule);
234 continue;
235 }
236
237 dstMac = getDstMacFromSelector(flowRule);
238 if (dstMac != null && dstMac.equals(mac)) {
239 processFlowRule(false, flowRule);
240 continue;
241 }
242
243 IpPrefix dstIp = getDstIpFromSelector(flowRule);
244 if (dstIp != null && dstIp.equals(ip.toIpPrefix())) {
245 processFlowRule(false, flowRule);
246 }
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800247 }
248
249 // TODO uninstall same network access rule in access table if no vm exists in the network
250 }
251
252 /**
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800253 * Populates service dependency rules.
254 *
255 * @param tService tenant cord service
256 * @param pService provider cord service
Hyunsun Moon640f183e2016-02-10 17:02:37 -0800257 * @param isBidirectional true to enable bidirectional connection between two services
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800258 */
Hyunsun Moon640f183e2016-02-10 17:02:37 -0800259 public void populateServiceDependencyRules(CordService tService, CordService pService,
260 boolean isBidirectional) {
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800261 checkNotNull(tService);
262 checkNotNull(pService);
263
264 Ip4Prefix srcRange = tService.serviceIpRange().getIp4Prefix();
265 Ip4Prefix dstRange = pService.serviceIpRange().getIp4Prefix();
266 Ip4Address serviceIp = pService.serviceIp().getIp4Address();
267
268 Map<DeviceId, GroupId> outGroups = Maps.newHashMap();
269 Map<DeviceId, Set<PortNumber>> inPorts = Maps.newHashMap();
270
271 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
272 GroupId groupId = createServiceGroup(device.id(), pService);
273 outGroups.put(device.id(), groupId);
274
275 Set<PortNumber> vms = tService.hosts().keySet()
276 .stream()
277 .filter(host -> host.location().deviceId().equals(device.id()))
278 .map(host -> host.location().port())
279 .collect(Collectors.toSet());
280 inPorts.put(device.id(), vms);
281 }
282
283 populateIndirectAccessRule(srcRange, serviceIp, outGroups);
284 populateDirectAccessRule(srcRange, dstRange);
Hyunsun Moon640f183e2016-02-10 17:02:37 -0800285 if (isBidirectional) {
286 populateDirectAccessRule(dstRange, srcRange);
287 }
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800288 populateInServiceRule(inPorts, outGroups);
289 }
290
291 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800292 * Removes service dependency rules.
293 *
294 * @param tService tenant cord service
295 * @param pService provider cord service
296 */
297 public void removeServiceDependencyRules(CordService tService, CordService pService) {
298 checkNotNull(tService);
299 checkNotNull(pService);
300
301 Ip4Prefix srcRange = tService.serviceIpRange().getIp4Prefix();
302 Ip4Prefix dstRange = pService.serviceIpRange().getIp4Prefix();
303 IpPrefix serviceIp = pService.serviceIp().toIpPrefix();
304
305 Map<DeviceId, GroupId> outGroups = Maps.newHashMap();
306 GroupKey groupKey = new DefaultGroupKey(pService.id().id().getBytes());
307
308 deviceService.getAvailableDevices(SWITCH).forEach(device -> {
309 Group group = groupService.getGroup(device.id(), groupKey);
310 if (group != null) {
311 outGroups.put(device.id(), group.id());
312 }
313 });
314
315 for (FlowRule flowRule : flowRuleService.getFlowRulesById(appId)) {
316 IpPrefix dstIp = getDstIpFromSelector(flowRule);
317 IpPrefix srcIp = getSrcIpFromSelector(flowRule);
318
319 if (dstIp != null && dstIp.equals(serviceIp)) {
320 processFlowRule(false, flowRule);
321 continue;
322 }
323
324 if (dstIp != null && srcIp != null) {
325 if (dstIp.equals(dstRange) && srcIp.equals(srcRange)) {
326 processFlowRule(false, flowRule);
327 continue;
328 }
329
330 if (dstIp.equals(srcRange) && srcIp.equals(dstRange)) {
331 processFlowRule(false, flowRule);
332 continue;
333 }
334 }
335
336 GroupId groupId = getGroupIdFromTreatment(flowRule);
337 if (groupId != null && groupId.equals(outGroups.get(flowRule.deviceId()))) {
338 processFlowRule(false, flowRule);
339 }
340 }
341
342 // TODO remove the group if it is not in use
343 }
344
345 /**
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800346 * Updates group buckets for a given service to all devices.
347 *
348 * @param service cord service
349 */
350 public void updateServiceGroup(CordService service) {
351 checkNotNull(service);
352
353 GroupKey groupKey = getGroupKey(service.id());
354
355 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
356 DeviceId deviceId = device.id();
357 if (!mastershipService.isLocalMaster(deviceId)) {
358 continue;
359 }
360
361 Group group = groupService.getGroup(deviceId, groupKey);
362 if (group == null) {
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800363 log.trace("No group exists for service {} in {}, do nothing.", service.id(), deviceId);
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800364 continue;
365 }
366
367 List<GroupBucket> oldBuckets = group.buckets().buckets();
368 List<GroupBucket> newBuckets = getServiceGroupBuckets(
369 deviceId, service.segmentationId(), service.hosts()).buckets();
370
371 if (oldBuckets.equals(newBuckets)) {
372 continue;
373 }
374
375 List<GroupBucket> bucketsToRemove = new ArrayList<>(oldBuckets);
376 bucketsToRemove.removeAll(newBuckets);
377 if (!bucketsToRemove.isEmpty()) {
378 groupService.removeBucketsFromGroup(
379 deviceId,
380 groupKey,
381 new GroupBuckets(bucketsToRemove),
382 groupKey, appId);
383 }
384
385 List<GroupBucket> bucketsToAdd = new ArrayList<>(newBuckets);
386 bucketsToAdd.removeAll(oldBuckets);
387 if (!bucketsToAdd.isEmpty()) {
388 groupService.addBucketsToGroup(
389 deviceId,
390 groupKey,
391 new GroupBuckets(bucketsToAdd),
392 groupKey, appId);
393 }
394 }
395 }
396
397 /**
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800398 * Populates flow rules for management network access.
399 *
400 * @param host host which has management network interface
401 * @param mService management network service
402 */
403 public void populateManagementNetworkRules(Host host, CordService mService) {
404 checkNotNull(mService);
405
406 DeviceId deviceId = host.location().deviceId();
407 IpAddress hostIp = host.ipAddresses().stream().findFirst().get();
408
409 TrafficSelector selector = DefaultTrafficSelector.builder()
410 .matchEthType(Ethernet.TYPE_ARP)
411 .matchArpTpa(mService.serviceIp().getIp4Address())
412 .build();
413
414 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
415 .setOutput(PortNumber.LOCAL)
416 .build();
417
418 FlowRule flowRule = DefaultFlowRule.builder()
419 .fromApp(appId)
420 .withSelector(selector)
421 .withTreatment(treatment)
422 .withPriority(MANAGEMENT_PRIORITY)
423 .forDevice(deviceId)
424 .forTable(TABLE_FIRST)
425 .makePermanent()
426 .build();
427
428 processFlowRule(true, flowRule);
429
430 selector = DefaultTrafficSelector.builder()
431 .matchInPort(PortNumber.LOCAL)
432 .matchEthType(Ethernet.TYPE_ARP)
433 .matchArpTpa(hostIp.getIp4Address())
434 .build();
435
436 treatment = DefaultTrafficTreatment.builder()
437 .setOutput(host.location().port())
438 .build();
439
440 flowRule = DefaultFlowRule.builder()
441 .fromApp(appId)
442 .withSelector(selector)
443 .withTreatment(treatment)
444 .withPriority(MANAGEMENT_PRIORITY)
445 .forDevice(deviceId)
446 .forTable(TABLE_FIRST)
447 .makePermanent()
448 .build();
449
450 processFlowRule(true, flowRule);
451
452 selector = DefaultTrafficSelector.builder()
453 .matchInPort(PortNumber.LOCAL)
454 .matchEthType(Ethernet.TYPE_IPV4)
455 .matchIPDst(mService.serviceIpRange())
456 .build();
457
458 treatment = DefaultTrafficTreatment.builder()
459 .transition(TABLE_DST_IP)
460 .build();
461
462 flowRule = DefaultFlowRule.builder()
463 .fromApp(appId)
464 .withSelector(selector)
465 .withTreatment(treatment)
466 .withPriority(MANAGEMENT_PRIORITY)
467 .forDevice(deviceId)
468 .forTable(TABLE_FIRST)
469 .makePermanent()
470 .build();
471
472 processFlowRule(true, flowRule);
473
474 selector = DefaultTrafficSelector.builder()
475 .matchEthType(Ethernet.TYPE_IPV4)
476 .matchIPDst(mService.serviceIp().toIpPrefix())
477 .build();
478
479 treatment = DefaultTrafficTreatment.builder()
480 .setOutput(PortNumber.LOCAL)
481 .build();
482
483 flowRule = DefaultFlowRule.builder()
484 .fromApp(appId)
485 .withSelector(selector)
486 .withTreatment(treatment)
487 .withPriority(MANAGEMENT_PRIORITY)
488 .forDevice(deviceId)
489 .forTable(TABLE_ACCESS_TYPE)
490 .makePermanent()
491 .build();
492
493 processFlowRule(true, flowRule);
494 }
495
496 /**
497 * Removes management network access rules.
498 *
499 * @param host host to be removed
500 * @param mService service for management network
501 */
502 public void removeManagementNetworkRules(Host host, CordService mService) {
503 checkNotNull(mService);
504
505 for (FlowRule flowRule : flowRuleService.getFlowRulesById(appId)) {
506 if (flowRule.deviceId().equals(host.location().deviceId())) {
507 PortNumber port = getOutputFromTreatment(flowRule);
508 if (port != null && port.equals(host.location().port())) {
509 processFlowRule(false, flowRule);
510 }
511 }
512
513 // TODO remove the other rules if mgmt network is not in use
514 }
515 }
516
517 /**
Hyunsun Moon4a915152016-01-14 16:56:26 -0800518 * Populates default rules on the first table.
Hyunsun Moon133fd792016-02-09 01:55:48 -0800519 * It includes the rules for shuttling vxlan-encapped packets between ovs and
520 * linux stack,and external network connectivity.
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800521 *
522 * @param deviceId device id
Hyunsun Moon133fd792016-02-09 01:55:48 -0800523 * @param dpPort data plane interface port number
524 * @param dpIp data plane ip address
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800525 */
Hyunsun Moon133fd792016-02-09 01:55:48 -0800526 private void processFirstTable(DeviceId deviceId, PortNumber dpPort, IpAddress dpIp) {
Hyunsun Moon4a915152016-01-14 16:56:26 -0800527 // take vxlan packet out onto the physical port
528 TrafficSelector selector = DefaultTrafficSelector.builder()
529 .matchInPort(PortNumber.LOCAL)
530 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800531
Hyunsun Moon4a915152016-01-14 16:56:26 -0800532 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Hyunsun Moon133fd792016-02-09 01:55:48 -0800533 .setOutput(dpPort)
Hyunsun Moon4a915152016-01-14 16:56:26 -0800534 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800535
Hyunsun Moon4a915152016-01-14 16:56:26 -0800536 FlowRule flowRule = DefaultFlowRule.builder()
537 .fromApp(appId)
538 .withSelector(selector)
539 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800540 .withPriority(HIGH_PRIORITY)
Hyunsun Moon4a915152016-01-14 16:56:26 -0800541 .forDevice(deviceId)
542 .forTable(TABLE_FIRST)
543 .makePermanent()
544 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800545
Hyunsun Moon4a915152016-01-14 16:56:26 -0800546 processFlowRule(true, flowRule);
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800547
Hyunsun Moon4a915152016-01-14 16:56:26 -0800548 // take a vxlan encap'd packet through the Linux stack
549 selector = DefaultTrafficSelector.builder()
Hyunsun Moon133fd792016-02-09 01:55:48 -0800550 .matchInPort(dpPort)
Hyunsun Moon4a915152016-01-14 16:56:26 -0800551 .matchEthType(Ethernet.TYPE_IPV4)
552 .matchIPProtocol(IPv4.PROTOCOL_UDP)
553 .matchUdpDst(TpPort.tpPort(VXLAN_UDP_PORT))
554 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800555
Hyunsun Moon4a915152016-01-14 16:56:26 -0800556 treatment = DefaultTrafficTreatment.builder()
557 .setOutput(PortNumber.LOCAL)
558 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800559
Hyunsun Moon4a915152016-01-14 16:56:26 -0800560 flowRule = DefaultFlowRule.builder()
561 .fromApp(appId)
562 .withSelector(selector)
563 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800564 .withPriority(HIGH_PRIORITY)
Hyunsun Moon4a915152016-01-14 16:56:26 -0800565 .forDevice(deviceId)
566 .forTable(TABLE_FIRST)
567 .makePermanent()
568 .build();
569
570 processFlowRule(true, flowRule);
571
Hyunsun Moon133fd792016-02-09 01:55:48 -0800572 // take a packet to the data plane ip through Linux stack
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800573 selector = DefaultTrafficSelector.builder()
Hyunsun Moon133fd792016-02-09 01:55:48 -0800574 .matchInPort(dpPort)
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800575 .matchEthType(Ethernet.TYPE_IPV4)
Hyunsun Moon133fd792016-02-09 01:55:48 -0800576 .matchIPDst(dpIp.toIpPrefix())
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800577 .build();
578
579 treatment = DefaultTrafficTreatment.builder()
580 .setOutput(PortNumber.LOCAL)
581 .build();
582
583 flowRule = DefaultFlowRule.builder()
584 .fromApp(appId)
585 .withSelector(selector)
586 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800587 .withPriority(HIGH_PRIORITY)
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800588 .forDevice(deviceId)
589 .forTable(TABLE_FIRST)
590 .makePermanent()
591 .build();
592
593 processFlowRule(true, flowRule);
594
595 // take an arp packet from physical through Linux stack
596 selector = DefaultTrafficSelector.builder()
Hyunsun Moon133fd792016-02-09 01:55:48 -0800597 .matchInPort(dpPort)
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800598 .matchEthType(Ethernet.TYPE_ARP)
599 .build();
600
601 treatment = DefaultTrafficTreatment.builder()
602 .setOutput(PortNumber.LOCAL)
603 .build();
604
605 flowRule = DefaultFlowRule.builder()
606 .fromApp(appId)
607 .withSelector(selector)
608 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800609 .withPriority(HIGH_PRIORITY)
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800610 .forDevice(deviceId)
611 .forTable(TABLE_FIRST)
612 .makePermanent()
613 .build();
614
615 processFlowRule(true, flowRule);
616
Hyunsun Moon4a915152016-01-14 16:56:26 -0800617 // take all else to the next table
618 selector = DefaultTrafficSelector.builder()
619 .build();
620
621 treatment = DefaultTrafficTreatment.builder()
622 .transition(TABLE_IN_PORT)
623 .build();
624
625 flowRule = DefaultFlowRule.builder()
626 .fromApp(appId)
627 .withSelector(selector)
628 .withTreatment(treatment)
629 .withPriority(LOWEST_PRIORITY)
630 .forDevice(deviceId)
631 .forTable(TABLE_FIRST)
632 .makePermanent()
633 .build();
634
635 processFlowRule(true, flowRule);
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800636 }
637
638 /**
Hyunsun Moon133fd792016-02-09 01:55:48 -0800639 * Forward table miss packets in ACCESS_TYPE table to data plane port.
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800640 *
641 * @param deviceId device id
Hyunsun Moon133fd792016-02-09 01:55:48 -0800642 * @param dpPort data plane interface port number
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800643 */
Hyunsun Moon133fd792016-02-09 01:55:48 -0800644 private void processAccessTypeTable(DeviceId deviceId, PortNumber dpPort) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800645 TrafficSelector selector = DefaultTrafficSelector.builder()
646 .build();
647
648 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Hyunsun Moon133fd792016-02-09 01:55:48 -0800649 .setOutput(dpPort)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800650 .build();
651
652 FlowRule flowRule = DefaultFlowRule.builder()
653 .fromApp(appId)
654 .withSelector(selector)
655 .withTreatment(treatment)
656 .withPriority(LOWEST_PRIORITY)
657 .forDevice(deviceId)
658 .forTable(TABLE_ACCESS_TYPE)
659 .makePermanent()
660 .build();
661
662 processFlowRule(true, flowRule);
663 }
664
665 /**
Hyunsun Moon4a915152016-01-14 16:56:26 -0800666 * Populates default rules for IN_PORT table.
667 * All packets from tunnel port are forwarded to TUNNEL_ID table and all packets
Hyunsun Moon133fd792016-02-09 01:55:48 -0800668 * from data plane interface port to ACCESS_TYPE table.
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800669 *
670 * @param deviceId device id to install the rules
Hyunsun Moon4a915152016-01-14 16:56:26 -0800671 * @param tunnelPort tunnel port number
Hyunsun Moon133fd792016-02-09 01:55:48 -0800672 * @param dpPort data plane interface port number
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800673 */
Hyunsun Moon133fd792016-02-09 01:55:48 -0800674 private void processInPortTable(DeviceId deviceId, PortNumber tunnelPort, PortNumber dpPort) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800675 checkNotNull(tunnelPort);
676
677 TrafficSelector selector = DefaultTrafficSelector.builder()
678 .matchInPort(tunnelPort)
679 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800680
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800681 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
682 .transition(TABLE_TUNNEL_IN)
683 .build();
684
685 FlowRule flowRule = DefaultFlowRule.builder()
686 .fromApp(appId)
687 .withSelector(selector)
688 .withTreatment(treatment)
689 .withPriority(DEFAULT_PRIORITY)
690 .forDevice(deviceId)
691 .forTable(TABLE_IN_PORT)
692 .makePermanent()
693 .build();
694
695 processFlowRule(true, flowRule);
Hyunsun Moon4a915152016-01-14 16:56:26 -0800696
697 selector = DefaultTrafficSelector.builder()
Hyunsun Moon133fd792016-02-09 01:55:48 -0800698 .matchInPort(dpPort)
Hyunsun Moon4a915152016-01-14 16:56:26 -0800699 .build();
700
701 treatment = DefaultTrafficTreatment.builder()
702 .transition(TABLE_DST_IP)
703 .build();
704
705 flowRule = DefaultFlowRule.builder()
706 .fromApp(appId)
707 .withSelector(selector)
708 .withTreatment(treatment)
709 .withPriority(DEFAULT_PRIORITY)
710 .forDevice(deviceId)
711 .forTable(TABLE_IN_PORT)
712 .makePermanent()
713 .build();
714
715 processFlowRule(true, flowRule);
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800716 }
717
718 /**
719 * Populates rules for local in port in IN_PORT table.
720 * Flows from a given in port, whose source IP is service IP transition
721 * to DST_TYPE table. Other flows transition to IN_SERVICE table.
722 *
723 * @param deviceId device id to install the rules
724 * @param inPort in port
725 * @param srcIp source ip
726 */
727 private void populateLocalInPortRule(DeviceId deviceId, PortNumber inPort, IpAddress srcIp) {
728 TrafficSelector selector = DefaultTrafficSelector.builder()
729 .matchInPort(inPort)
730 .matchEthType(Ethernet.TYPE_IPV4)
731 .matchIPSrc(srcIp.toIpPrefix())
732 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800733
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800734 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
735 .transition(TABLE_ACCESS_TYPE)
736 .build();
737
738
739 FlowRule flowRule = DefaultFlowRule.builder()
740 .fromApp(appId)
741 .withSelector(selector)
742 .withTreatment(treatment)
743 .withPriority(DEFAULT_PRIORITY)
744 .forDevice(deviceId)
745 .forTable(TABLE_IN_PORT)
746 .makePermanent()
747 .build();
748
749 processFlowRule(true, flowRule);
750
751 selector = DefaultTrafficSelector.builder()
752 .matchInPort(inPort)
753 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800754
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800755 treatment = DefaultTrafficTreatment.builder()
756 .transition(TABLE_IN_SERVICE)
757 .build();
758
759 flowRule = DefaultFlowRule.builder()
760 .fromApp(appId)
761 .withSelector(selector)
762 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800763 .withPriority(LOW_PRIORITY)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800764 .forDevice(deviceId)
765 .forTable(TABLE_IN_PORT)
766 .makePermanent()
767 .build();
768
769 processFlowRule(true, flowRule);
770 }
771
772 /**
773 * Populates direct VM access rules for ACCESS_TYPE table.
774 * These rules are installed to all devices.
775 *
776 * @param srcRange source ip range
777 * @param dstRange destination ip range
778 */
779 private void populateDirectAccessRule(Ip4Prefix srcRange, Ip4Prefix dstRange) {
780 TrafficSelector selector = DefaultTrafficSelector.builder()
781 .matchEthType(Ethernet.TYPE_IPV4)
782 .matchIPSrc(srcRange)
783 .matchIPDst(dstRange)
784 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800785
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800786 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
787 .transition(TABLE_DST_IP)
788 .build();
789
790 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
791 FlowRule flowRuleDirect = DefaultFlowRule.builder()
792 .fromApp(appId)
793 .withSelector(selector)
794 .withTreatment(treatment)
Hyunsun Moon81ab23b2016-02-01 23:00:56 -0800795 .withPriority(DEFAULT_PRIORITY)
796 .forDevice(device.id())
797 .forTable(TABLE_ACCESS_TYPE)
798 .makePermanent()
799 .build();
800
801 processFlowRule(true, flowRuleDirect);
802 }
803 }
804
805 /**
806 * Populates drop rules that does not match any direct access rules but has
807 * destination to a different service network in ACCESS_TYPE table.
808 *
809 * @param dstRange destination ip range
810 */
811 private void populateServiceIsolationRule(Ip4Prefix dstRange) {
812 TrafficSelector selector = DefaultTrafficSelector.builder()
813 .matchEthType(Ethernet.TYPE_IPV4)
814 .matchIPDst(dstRange)
815 .build();
816
817 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
818 .drop()
819 .build();
820
821 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
822 FlowRule flowRuleDirect = DefaultFlowRule.builder()
823 .fromApp(appId)
824 .withSelector(selector)
825 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800826 .withPriority(LOW_PRIORITY)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800827 .forDevice(device.id())
828 .forTable(TABLE_ACCESS_TYPE)
829 .makePermanent()
830 .build();
831
832 processFlowRule(true, flowRuleDirect);
833 }
834 }
835
836 /**
837 * Populates indirect service access rules for ACCESS_TYPE table.
838 * These rules are installed to all devices.
839 *
840 * @param srcRange source range
841 * @param serviceIp service ip
842 * @param outGroups list of output group
843 */
844 private void populateIndirectAccessRule(Ip4Prefix srcRange, Ip4Address serviceIp,
845 Map<DeviceId, GroupId> outGroups) {
846 TrafficSelector selector = DefaultTrafficSelector.builder()
847 .matchEthType(Ethernet.TYPE_IPV4)
848 .matchIPSrc(srcRange)
849 .matchIPDst(serviceIp.toIpPrefix())
850 .build();
851
852 for (Map.Entry<DeviceId, GroupId> outGroup : outGroups.entrySet()) {
853 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
854 .group(outGroup.getValue())
855 .build();
856
857 FlowRule flowRule = DefaultFlowRule.builder()
858 .fromApp(appId)
859 .withSelector(selector)
860 .withTreatment(treatment)
Hyunsun Moon81ab23b2016-02-01 23:00:56 -0800861 .withPriority(HIGH_PRIORITY)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800862 .forDevice(outGroup.getKey())
863 .forTable(TABLE_ACCESS_TYPE)
864 .makePermanent()
865 .build();
866
867 processFlowRule(true, flowRule);
868 }
869 }
870
871 /**
872 * Populates flow rules for IN_SERVICE table.
873 *
874 * @param inPorts list of inports related to the service for each device
875 * @param outGroups set of output groups
876 */
877 private void populateInServiceRule(Map<DeviceId, Set<PortNumber>> inPorts, Map<DeviceId, GroupId> outGroups) {
878 checkNotNull(inPorts);
879 checkNotNull(outGroups);
880
881 for (Map.Entry<DeviceId, Set<PortNumber>> entry : inPorts.entrySet()) {
882 Set<PortNumber> ports = entry.getValue();
883 DeviceId deviceId = entry.getKey();
884
885 GroupId groupId = outGroups.get(deviceId);
886 if (groupId == null) {
887 continue;
888 }
889
890 ports.stream().forEach(port -> {
891 TrafficSelector selector = DefaultTrafficSelector.builder()
892 .matchInPort(port)
893 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800894
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800895 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
896 .group(groupId)
897 .build();
898
899 FlowRule flowRule = DefaultFlowRule.builder()
900 .fromApp(appId)
901 .withSelector(selector)
902 .withTreatment(treatment)
903 .withPriority(DEFAULT_PRIORITY)
904 .forDevice(deviceId)
905 .forTable(TABLE_IN_SERVICE)
906 .makePermanent()
907 .build();
908
909 processFlowRule(true, flowRule);
910 });
911 }
912 }
913
914 /**
915 * Populates flow rules for DST_IP table.
916 *
917 * @param deviceId device id
918 * @param inPort in port
919 * @param dstMac mac address
920 * @param dstIp destination ip
921 * @param tunnelId tunnel id
922 * @param tunnelIp tunnel remote ip
923 */
924 private void populateDstIpRule(DeviceId deviceId, PortNumber inPort, MacAddress dstMac,
925 IpAddress dstIp, long tunnelId, IpAddress tunnelIp) {
926 TrafficSelector selector = DefaultTrafficSelector.builder()
927 .matchEthType(Ethernet.TYPE_IPV4)
928 .matchIPDst(dstIp.toIpPrefix())
929 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800930
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800931 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
932 .setEthDst(dstMac)
933 .setOutput(inPort)
934 .build();
935
936 FlowRule flowRule = DefaultFlowRule.builder()
937 .fromApp(appId)
938 .withSelector(selector)
939 .withTreatment(treatment)
940 .withPriority(DEFAULT_PRIORITY)
941 .forDevice(deviceId)
942 .forTable(TABLE_DST_IP)
943 .makePermanent()
944 .build();
945
946 processFlowRule(true, flowRule);
947
948 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
949 if (device.id().equals(deviceId)) {
950 continue;
951 }
952
953 ExtensionTreatment tunnelDst = getTunnelDst(device.id(), tunnelIp.getIp4Address());
954 if (tunnelDst == null) {
955 continue;
956 }
957
958 treatment = DefaultTrafficTreatment.builder()
959 .setEthDst(dstMac)
960 .setTunnelId(tunnelId)
961 .extension(tunnelDst, device.id())
962 .setOutput(getTunnelPort(device.id()))
963 .build();
964
965 flowRule = DefaultFlowRule.builder()
966 .fromApp(appId)
967 .withSelector(selector)
968 .withTreatment(treatment)
969 .withPriority(DEFAULT_PRIORITY)
970 .forDevice(device.id())
971 .forTable(TABLE_DST_IP)
972 .makePermanent()
973 .build();
974
975 processFlowRule(true, flowRule);
976 }
977 }
978
979 /**
980 * Populates flow rules for TUNNEL_ID table.
981 *
982 * @param deviceId device id
983 * @param inPort in port
984 * @param mac mac address
985 * @param tunnelId tunnel id
986 */
987 private void populateTunnelInRule(DeviceId deviceId, PortNumber inPort, MacAddress mac, long tunnelId) {
988 TrafficSelector selector = DefaultTrafficSelector.builder()
989 .matchTunnelId(tunnelId)
990 .matchEthDst(mac)
991 .build();
992
993 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
994 .setOutput(inPort)
995 .build();
996
997 FlowRule flowRule = DefaultFlowRule.builder()
998 .fromApp(appId)
999 .withSelector(selector)
1000 .withTreatment(treatment)
1001 .withPriority(DEFAULT_PRIORITY)
1002 .forDevice(deviceId)
1003 .forTable(TABLE_TUNNEL_IN)
1004 .makePermanent()
1005 .build();
1006
1007 processFlowRule(true, flowRule);
1008 }
1009
1010 /**
1011 * Installs or uninstall a given rule.
1012 *
1013 * @param install true to install, false to uninstall
1014 * @param rule rule
1015 */
1016 private void processFlowRule(boolean install, FlowRule rule) {
1017 FlowRuleOperations.Builder oBuilder = FlowRuleOperations.builder();
1018 oBuilder = install ? oBuilder.add(rule) : oBuilder.remove(rule);
1019
1020 flowRuleService.apply(oBuilder.build(new FlowRuleOperationsContext() {
1021 @Override
1022 public void onError(FlowRuleOperations ops) {
1023 log.error(String.format("Failed %s, %s", ops.toString(), rule.toString()));
1024 }
1025 }));
1026 }
1027
1028 /**
1029 * Returns tunnel port of the device.
1030 *
1031 * @param deviceId device id
1032 * @return tunnel port number, or null if no tunnel port exists on a given device
1033 */
1034 private PortNumber getTunnelPort(DeviceId deviceId) {
Hyunsun Moon5a4346f2016-01-15 11:41:14 -08001035 Port port = deviceService.getPorts(deviceId).stream()
Hyunsun Moon133fd792016-02-09 01:55:48 -08001036 .filter(p -> p.annotations().value(PORT_NAME).contains(tunnelType))
Hyunsun Moon5a4346f2016-01-15 11:41:14 -08001037 .findFirst().orElse(null);
1038
1039 return port == null ? null : port.number();
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001040 }
1041
1042 /**
Hyunsun Moon133fd792016-02-09 01:55:48 -08001043 * Returns data plane interface port name of a given device.
Hyunsun Moon4a915152016-01-14 16:56:26 -08001044 *
1045 * @param deviceId device id
Hyunsun Moon133fd792016-02-09 01:55:48 -08001046 * @param dpIntf data plane interface port name
1047 * @return data plane interface port number, or null if no such port exists
Hyunsun Moon4a915152016-01-14 16:56:26 -08001048 */
Hyunsun Moon133fd792016-02-09 01:55:48 -08001049 private PortNumber getDpPort(DeviceId deviceId, String dpIntf) {
Hyunsun Moon5a4346f2016-01-15 11:41:14 -08001050 Port port = deviceService.getPorts(deviceId).stream()
Hyunsun Moon133fd792016-02-09 01:55:48 -08001051 .filter(p -> p.annotations().value(PORT_NAME).contains(dpIntf) &&
Hyunsun Moon4a915152016-01-14 16:56:26 -08001052 p.isEnabled())
Hyunsun Moon5a4346f2016-01-15 11:41:14 -08001053 .findFirst().orElse(null);
1054
1055 return port == null ? null : port.number();
Hyunsun Moon4a915152016-01-14 16:56:26 -08001056 }
1057
1058 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001059 * Returns the inport from a given flow rule if the rule contains the match of it.
1060 *
1061 * @param flowRule flow rule
1062 * @return port number, or null if the rule doesn't have inport match
1063 */
1064 private PortNumber getInPort(FlowRule flowRule) {
1065 Criterion criterion = flowRule.selector().getCriterion(IN_PORT);
1066 if (criterion != null && criterion instanceof PortCriterion) {
1067 PortCriterion port = (PortCriterion) criterion;
1068 return port.port();
1069 } else {
1070 return null;
1071 }
1072 }
1073
1074 /**
1075 * Returns the destination mac address from a given flow rule if the rule
1076 * contains the instruction of it.
1077 *
1078 * @param flowRule flow rule
1079 * @return mac address, or null if the rule doesn't have destination mac instruction
1080 */
1081 private MacAddress getDstMacFromTreatment(FlowRule flowRule) {
1082 Instruction instruction = flowRule.treatment().allInstructions().stream()
1083 .filter(inst -> inst instanceof ModEtherInstruction &&
1084 ((ModEtherInstruction) inst).subtype().equals(ETH_DST))
1085 .findFirst()
1086 .orElse(null);
1087
1088 if (instruction == null) {
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001089 return null;
1090 }
1091
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001092 return ((ModEtherInstruction) instruction).mac();
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001093 }
1094
1095 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001096 * Returns the destination mac address from a given flow rule if the rule
1097 * contains the match of it.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001098 *
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001099 * @param flowRule flow rule
1100 * @return mac address, or null if the rule doesn't have destination mac match
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001101 */
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001102 private MacAddress getDstMacFromSelector(FlowRule flowRule) {
1103 Criterion criterion = flowRule.selector().getCriterion(Criterion.Type.ETH_DST);
1104 if (criterion != null && criterion instanceof EthCriterion) {
1105 EthCriterion eth = (EthCriterion) criterion;
1106 return eth.mac();
1107 } else {
1108 return null;
1109 }
1110 }
1111
1112 /**
1113 * Returns the destination IP from a given flow rule if the rule contains
1114 * the match of it.
1115 *
1116 * @param flowRule flow rule
1117 * @return ip prefix, or null if the rule doesn't have ip match
1118 */
1119 private IpPrefix getDstIpFromSelector(FlowRule flowRule) {
1120 Criterion criterion = flowRule.selector().getCriterion(IPV4_DST);
1121 if (criterion != null && criterion instanceof IPCriterion) {
1122 IPCriterion ip = (IPCriterion) criterion;
1123 return ip.ip();
1124 } else {
1125 return null;
1126 }
1127 }
1128
1129 /**
1130 * Returns the source IP from a given flow rule if the rule contains
1131 * the match of it.
1132 *
1133 * @param flowRule flow rule
1134 * @return ip prefix, or null if the rule doesn't have ip match
1135 */
1136 private IpPrefix getSrcIpFromSelector(FlowRule flowRule) {
1137 Criterion criterion = flowRule.selector().getCriterion(IPV4_SRC);
1138 if (criterion != null && criterion instanceof IPCriterion) {
1139 IPCriterion ip = (IPCriterion) criterion;
1140 return ip.ip();
1141 } else {
1142 return null;
1143 }
1144 }
1145
1146 /**
1147 * Returns the group ID from a given flow rule if the rule contains the
1148 * treatment of it.
1149 *
1150 * @param flowRule flow rule
1151 * @return group id, or null if the rule doesn't have group instruction
1152 */
1153 private GroupId getGroupIdFromTreatment(FlowRule flowRule) {
1154 Instruction instruction = flowRule.treatment().allInstructions().stream()
1155 .filter(inst -> inst instanceof Instructions.GroupInstruction)
1156 .findFirst()
1157 .orElse(null);
1158
1159 if (instruction == null) {
1160 return null;
1161 }
1162
1163 return ((Instructions.GroupInstruction) instruction).groupId();
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001164 }
1165
1166 /**
Hyunsun Moond52bffc2016-01-29 18:57:05 -08001167 * Returns the output port number from a given flow rule.
1168 *
1169 * @param flowRule flow rule
1170 * @return port number, or null if the rule does not have output instruction
1171 */
1172 private PortNumber getOutputFromTreatment(FlowRule flowRule) {
1173 Instruction instruction = flowRule.treatment().allInstructions().stream()
1174 .filter(inst -> inst instanceof Instructions.OutputInstruction)
1175 .findFirst()
1176 .orElse(null);
1177
1178 if (instruction == null) {
1179 return null;
1180 }
1181
1182 return ((Instructions.OutputInstruction) instruction).port();
1183 }
1184
1185 /**
Hyunsun Moon4a915152016-01-14 16:56:26 -08001186 * Creates a new group for a given service.
1187 *
1188 * @param deviceId device id to create a group
1189 * @param service cord service
1190 * @return group id, or null if it fails to create
1191 */
1192 private GroupId createServiceGroup(DeviceId deviceId, CordService service) {
1193 checkNotNull(service);
1194
1195 GroupKey groupKey = getGroupKey(service.id());
1196 Group group = groupService.getGroup(deviceId, groupKey);
1197 GroupId groupId = getGroupId(service.id(), deviceId);
1198
1199 if (group != null) {
1200 log.debug("Group {} is already exist in {}", service.id(), deviceId);
1201 return groupId;
1202 }
1203
1204 GroupBuckets buckets = getServiceGroupBuckets(deviceId, service.segmentationId(), service.hosts());
1205 GroupDescription groupDescription = new DefaultGroupDescription(
1206 deviceId,
1207 GroupDescription.Type.SELECT,
1208 buckets,
1209 groupKey,
1210 groupId.id(),
1211 appId);
1212
1213 groupService.addGroup(groupDescription);
1214
1215 return groupId;
1216 }
1217
1218 /**
1219 * Returns group buckets for a given device.
1220 *
1221 * @param deviceId device id
1222 * @param tunnelId tunnel id
1223 * @param hosts list of host
1224 * @return group buckets
1225 */
1226 private GroupBuckets getServiceGroupBuckets(DeviceId deviceId, long tunnelId, Map<Host, IpAddress> hosts) {
1227 List<GroupBucket> buckets = Lists.newArrayList();
1228
1229 for (Map.Entry<Host, IpAddress> entry : hosts.entrySet()) {
1230 Host host = entry.getKey();
1231 Ip4Address remoteIp = entry.getValue().getIp4Address();
1232 DeviceId hostDevice = host.location().deviceId();
1233
1234 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
1235 .builder()
1236 .setEthDst(host.mac());
1237
1238 if (deviceId.equals(hostDevice)) {
1239 tBuilder.setOutput(host.location().port());
1240 } else {
1241 ExtensionTreatment tunnelDst = getTunnelDst(deviceId, remoteIp);
1242 if (tunnelDst == null) {
1243 continue;
1244 }
1245
1246 tBuilder.extension(tunnelDst, deviceId)
1247 .setTunnelId(tunnelId)
1248 .setOutput(getTunnelPort(hostDevice));
1249 }
1250
1251 buckets.add(DefaultGroupBucket.createSelectGroupBucket(tBuilder.build()));
1252 }
1253
1254 return new GroupBuckets(buckets);
1255 }
1256
1257 /**
1258 * Returns globally unique group ID.
1259 *
1260 * @param serviceId service id
1261 * @param deviceId device id
1262 * @return group id
1263 */
1264 private GroupId getGroupId(CordServiceId serviceId, DeviceId deviceId) {
1265 return new DefaultGroupId(Objects.hash(serviceId, deviceId));
1266 }
1267
1268 /**
1269 * Returns group key of a service.
1270 *
1271 * @param serviceId service id
1272 * @return group key
1273 */
1274 private GroupKey getGroupKey(CordServiceId serviceId) {
1275 return new DefaultGroupKey(serviceId.id().getBytes());
1276 }
1277
1278 /**
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001279 * Returns extension instruction to set tunnel destination.
1280 *
1281 * @param deviceId device id
1282 * @param remoteIp tunnel destination address
1283 * @return extension treatment or null if it fails to get instruction
1284 */
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001285 private ExtensionTreatment getTunnelDst(DeviceId deviceId, Ip4Address remoteIp) {
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001286 try {
1287 Driver driver = driverService.getDriver(deviceId);
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001288 DefaultDriverData driverData = new DefaultDriverData(driver, deviceId);
1289 DriverHandler handler = new DefaultDriverHandler(driverData);
1290 ExtensionTreatmentResolver resolver = handler.behaviour(ExtensionTreatmentResolver.class);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001291
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001292 ExtensionTreatment treatment =
1293 resolver.getExtensionInstruction(NICIRA_SET_TUNNEL_DST.type());
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001294 treatment.setPropertyValue("tunnelDst", remoteIp);
1295
1296 return treatment;
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001297 } catch (ItemNotFoundException | UnsupportedOperationException |
1298 ExtensionPropertyException e) {
1299 log.error("Failed to get extension instruction {}", deviceId);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001300 return null;
1301 }
1302 }
1303}
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001304