blob: ada68a949c11fe594d15cabde1afb7c006a0e221 [file] [log] [blame]
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08003 *
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 */
Hyunsun Moon7f4ed9d2016-04-14 16:13:42 -070016package org.onosproject.cordvtn.impl;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080017
Hyunsun Moonc71231d2015-12-16 20:53:23 -080018import com.google.common.collect.Lists;
19import com.google.common.collect.Maps;
Hyunsun Moonfae776d2016-03-08 18:07:52 -080020import com.google.common.collect.Sets;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080021import org.onlab.packet.Ethernet;
Hyunsun Moon4a915152016-01-14 16:56:26 -080022import org.onlab.packet.IPv4;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080023import org.onlab.packet.Ip4Address;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080024import org.onlab.packet.Ip4Prefix;
25import org.onlab.packet.IpAddress;
26import org.onlab.packet.IpPrefix;
27import org.onlab.packet.MacAddress;
Hyunsun Moon4a915152016-01-14 16:56:26 -080028import org.onlab.packet.TpPort;
Hyunsun Moon6d247342016-02-12 12:48:47 -080029import org.onlab.packet.VlanId;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080030import org.onlab.util.ItemNotFoundException;
Hyunsun Moon7f4ed9d2016-04-14 16:13:42 -070031import org.onosproject.cordvtn.api.CordService;
32import org.onosproject.cordvtn.api.CordServiceId;
33import org.onosproject.cordvtn.api.CordVtnConfig;
34import org.onosproject.cordvtn.api.CordVtnNode;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080035import org.onosproject.core.ApplicationId;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080036import org.onosproject.core.DefaultGroupId;
37import org.onosproject.core.GroupId;
Jian Li7532eb12016-04-15 13:22:05 -070038import org.onosproject.net.Device;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080039import org.onosproject.net.DeviceId;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080040import org.onosproject.net.Host;
Hyunsun Moon5a4346f2016-01-15 11:41:14 -080041import org.onosproject.net.Port;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080042import org.onosproject.net.PortNumber;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080043import org.onosproject.net.behaviour.ExtensionTreatmentResolver;
Hyunsun Moonfae776d2016-03-08 18:07:52 -080044import org.onosproject.net.config.NetworkConfigRegistry;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080045import org.onosproject.net.device.DeviceService;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080046import org.onosproject.net.flow.DefaultFlowRule;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080047import org.onosproject.net.flow.DefaultTrafficSelector;
48import org.onosproject.net.flow.DefaultTrafficTreatment;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080049import org.onosproject.net.flow.FlowRule;
50import org.onosproject.net.flow.FlowRuleOperations;
51import org.onosproject.net.flow.FlowRuleOperationsContext;
52import org.onosproject.net.flow.FlowRuleService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080053import org.onosproject.net.flow.TrafficSelector;
54import org.onosproject.net.flow.TrafficTreatment;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080055import org.onosproject.net.flow.criteria.Criterion;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080056import org.onosproject.net.flow.criteria.IPCriterion;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080057import org.onosproject.net.flow.instructions.ExtensionPropertyException;
58import org.onosproject.net.flow.instructions.ExtensionTreatment;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080059import org.onosproject.net.flow.instructions.Instruction;
60import org.onosproject.net.flow.instructions.Instructions;
Hyunsun Moon6d247342016-02-12 12:48:47 -080061import org.onosproject.net.flow.instructions.L2ModificationInstruction;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080062import org.onosproject.net.group.DefaultGroupBucket;
63import org.onosproject.net.group.DefaultGroupDescription;
64import org.onosproject.net.group.DefaultGroupKey;
65import org.onosproject.net.group.Group;
66import org.onosproject.net.group.GroupBucket;
67import org.onosproject.net.group.GroupBuckets;
68import org.onosproject.net.group.GroupDescription;
69import org.onosproject.net.group.GroupKey;
70import org.onosproject.net.group.GroupService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080071import org.slf4j.Logger;
72
Hyunsun Moon4161e6f2016-01-07 01:32:31 -080073import java.util.ArrayList;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080074import java.util.List;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080075import java.util.Map;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080076import java.util.Objects;
77import java.util.Set;
78import java.util.stream.Collectors;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080079
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080080import static com.google.common.base.Preconditions.checkNotNull;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080081import static org.onosproject.net.flow.criteria.Criterion.Type.IPV4_DST;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080082import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST;
Hyunsun Moon6d247342016-02-12 12:48:47 -080083import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.VLAN_PUSH;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080084import static org.slf4j.LoggerFactory.getLogger;
85
86/**
Hyunsun Moonc71231d2015-12-16 20:53:23 -080087 * Populates rules for CORD VTN service.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080088 */
Hyunsun Moonc71231d2015-12-16 20:53:23 -080089public class CordVtnRuleInstaller {
90
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080091 protected final Logger log = getLogger(getClass());
92
Hyunsun Moon4a915152016-01-14 16:56:26 -080093 private static final int TABLE_FIRST = 0;
94 private static final int TABLE_IN_PORT = 1;
95 private static final int TABLE_ACCESS_TYPE = 2;
96 private static final int TABLE_IN_SERVICE = 3;
97 private static final int TABLE_DST_IP = 4;
98 private static final int TABLE_TUNNEL_IN = 5;
Hyunsun Moon6d247342016-02-12 12:48:47 -080099 private static final int TABLE_Q_IN_Q = 6;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800100
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800101 private static final int MANAGEMENT_PRIORITY = 55000;
Hyunsun Moon6d247342016-02-12 12:48:47 -0800102 private static final int VSG_PRIORITY = 55000;
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800103 private static final int HIGH_PRIORITY = 50000;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800104 private static final int DEFAULT_PRIORITY = 5000;
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800105 private static final int LOW_PRIORITY = 4000;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800106 private static final int LOWEST_PRIORITY = 0;
Hyunsun Moon4a915152016-01-14 16:56:26 -0800107
108 private static final int VXLAN_UDP_PORT = 4789;
Hyunsun Moon6d247342016-02-12 12:48:47 -0800109 private static final VlanId VLAN_WAN = VlanId.vlanId((short) 500);
110
111 private static final String PORT_NAME = "portName";
112 private static final String DATA_PLANE_INTF = "dataPlaneIntf";
Hyunsun Moonc14be422016-04-27 15:06:56 -0500113 private static final String DATA_PLANE_IP = "dataPlaneIp";
Hyunsun Moon6d247342016-02-12 12:48:47 -0800114 private static final String S_TAG = "stag";
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800115
116 private final ApplicationId appId;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800117 private final FlowRuleService flowRuleService;
118 private final DeviceService deviceService;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800119 private final GroupService groupService;
Hyunsun Moonfae776d2016-03-08 18:07:52 -0800120 private final NetworkConfigRegistry configRegistry;
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
Jian Lidfba7392016-01-22 16:46:58 -0800129 * @param groupService group service
Ray Milkeyd4334db2016-04-05 17:39:44 -0700130 * @param configRegistry config registry
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 Moonc71231d2015-12-16 20:53:23 -0800136 GroupService groupService,
Hyunsun Moonfae776d2016-03-08 18:07:52 -0800137 NetworkConfigRegistry configRegistry,
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800138 String tunnelType) {
139 this.appId = appId;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800140 this.flowRuleService = flowRuleService;
141 this.deviceService = deviceService;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800142 this.groupService = groupService;
Hyunsun Moonfae776d2016-03-08 18:07:52 -0800143 this.configRegistry = configRegistry;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800144 this.tunnelType = checkNotNull(tunnelType);
145 }
146
147 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800148 * Installs table miss rule to a give device.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800149 *
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800150 * @param deviceId device id to install the rules
Hyunsun Moon133fd792016-02-09 01:55:48 -0800151 * @param dpIntf data plane interface name
152 * @param dpIp data plane ip address
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800153 */
Hyunsun Moon133fd792016-02-09 01:55:48 -0800154 public void init(DeviceId deviceId, String dpIntf, IpAddress dpIp) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800155 // default is drop packets which can be accomplished without
156 // a table miss entry for all table.
Hyunsun Moon4a915152016-01-14 16:56:26 -0800157 PortNumber tunnelPort = getTunnelPort(deviceId);
Hyunsun Moon133fd792016-02-09 01:55:48 -0800158 PortNumber dpPort = getDpPort(deviceId, dpIntf);
Hyunsun Moon4a915152016-01-14 16:56:26 -0800159
Hyunsun Moon133fd792016-02-09 01:55:48 -0800160 processFirstTable(deviceId, dpPort, dpIp);
161 processInPortTable(deviceId, tunnelPort, dpPort);
162 processAccessTypeTable(deviceId, dpPort);
Hyunsun Moon6d247342016-02-12 12:48:47 -0800163 processQInQTable(deviceId, dpPort);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800164 }
165
166 /**
Hyunsun Moon2062e7e2016-03-08 15:37:57 -0800167 * Flush flows installed by this application.
168 */
169 public void flushRules() {
170 flowRuleService.getFlowRulesById(appId).forEach(flowRule -> processFlowRule(false, flowRule));
171 }
172
173 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800174 * Populates basic rules that connect a VM to the other VMs in the system.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800175 *
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800176 * @param host host
Hyunsun Moonc14be422016-04-27 15:06:56 -0500177 * @param service cord service
178 * @param install true to install or false to remove
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800179 */
Hyunsun Moonc14be422016-04-27 15:06:56 -0500180 public void populateBasicConnectionRules(Host host, CordService service, boolean install) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800181 checkNotNull(host);
Hyunsun Moonc14be422016-04-27 15:06:56 -0500182 checkNotNull(service);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800183
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800184 DeviceId deviceId = host.location().deviceId();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800185 PortNumber inPort = host.location().port();
186 MacAddress dstMac = host.mac();
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800187 IpAddress hostIp = host.ipAddresses().stream().findFirst().get();
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800188
Hyunsun Moonc14be422016-04-27 15:06:56 -0500189 long tunnelId = service.segmentationId();
190 Ip4Prefix serviceIpRange = service.serviceIpRange().getIp4Prefix();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800191
Hyunsun Moonc14be422016-04-27 15:06:56 -0500192 populateLocalInPortRule(deviceId, inPort, hostIp, install);
193 populateDstIpRule(deviceId, inPort, dstMac, hostIp, tunnelId, getTunnelIp(host), install);
194 populateTunnelInRule(deviceId, inPort, dstMac, tunnelId, install);
195
196 if (install) {
197 populateDirectAccessRule(serviceIpRange, serviceIpRange, true);
198 populateServiceIsolationRule(serviceIpRange, true);
199 } else if (service.hosts().isEmpty()) {
200 // removes network related rules only if there's no hosts left in this network
201 populateDirectAccessRule(serviceIpRange, serviceIpRange, false);
202 populateServiceIsolationRule(serviceIpRange, false);
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800203 }
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800204 }
205
206 /**
Hyunsun Moonc14be422016-04-27 15:06:56 -0500207 * Creates provider service group and populates service dependency rules.
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800208 *
209 * @param tService tenant cord service
210 * @param pService provider cord service
Hyunsun Moon640f183e2016-02-10 17:02:37 -0800211 * @param isBidirectional true to enable bidirectional connection between two services
Hyunsun Moonc14be422016-04-27 15:06:56 -0500212 * @param install true to install or false to remove
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800213 */
Hyunsun Moon640f183e2016-02-10 17:02:37 -0800214 public void populateServiceDependencyRules(CordService tService, CordService pService,
Hyunsun Moonc14be422016-04-27 15:06:56 -0500215 boolean isBidirectional, boolean install) {
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800216 checkNotNull(tService);
217 checkNotNull(pService);
218
219 Ip4Prefix srcRange = tService.serviceIpRange().getIp4Prefix();
220 Ip4Prefix dstRange = pService.serviceIpRange().getIp4Prefix();
221 Ip4Address serviceIp = pService.serviceIp().getIp4Address();
222
223 Map<DeviceId, GroupId> outGroups = Maps.newHashMap();
224 Map<DeviceId, Set<PortNumber>> inPorts = Maps.newHashMap();
225
Hyunsun Moonfae776d2016-03-08 18:07:52 -0800226 getVirtualSwitches().stream().forEach(deviceId -> {
227 GroupId groupId = createServiceGroup(deviceId, pService);
228 outGroups.put(deviceId, groupId);
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800229
Hyunsun Moondd91be22016-04-24 17:43:32 -0700230 Set<PortNumber> tServiceVms = tService.hosts().keySet()
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800231 .stream()
Hyunsun Moonfae776d2016-03-08 18:07:52 -0800232 .filter(host -> host.location().deviceId().equals(deviceId))
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800233 .map(host -> host.location().port())
234 .collect(Collectors.toSet());
Hyunsun Moondd91be22016-04-24 17:43:32 -0700235 inPorts.put(deviceId, tServiceVms);
Hyunsun Moonfae776d2016-03-08 18:07:52 -0800236 });
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800237
Hyunsun Moonc14be422016-04-27 15:06:56 -0500238 populateIndirectAccessRule(srcRange, serviceIp, outGroups, install);
239 populateDirectAccessRule(srcRange, dstRange, install);
Hyunsun Moon640f183e2016-02-10 17:02:37 -0800240 if (isBidirectional) {
Hyunsun Moonc14be422016-04-27 15:06:56 -0500241 populateDirectAccessRule(dstRange, srcRange, install);
Hyunsun Moon640f183e2016-02-10 17:02:37 -0800242 }
Hyunsun Moonc14be422016-04-27 15:06:56 -0500243 populateInServiceRule(inPorts, outGroups, install);
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800244 }
245
246 /**
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800247 * Updates group buckets for a given service to all devices.
248 *
249 * @param service cord service
250 */
Hyunsun Moonc14be422016-04-27 15:06:56 -0500251 public void updateProviderServiceGroup(CordService service) {
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800252 checkNotNull(service);
253
254 GroupKey groupKey = getGroupKey(service.id());
255
Hyunsun Moonfae776d2016-03-08 18:07:52 -0800256 for (DeviceId deviceId : getVirtualSwitches()) {
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800257 Group group = groupService.getGroup(deviceId, groupKey);
258 if (group == null) {
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800259 log.trace("No group exists for service {} in {}, do nothing.", service.id(), deviceId);
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800260 continue;
261 }
262
263 List<GroupBucket> oldBuckets = group.buckets().buckets();
264 List<GroupBucket> newBuckets = getServiceGroupBuckets(
265 deviceId, service.segmentationId(), service.hosts()).buckets();
266
267 if (oldBuckets.equals(newBuckets)) {
268 continue;
269 }
270
271 List<GroupBucket> bucketsToRemove = new ArrayList<>(oldBuckets);
272 bucketsToRemove.removeAll(newBuckets);
273 if (!bucketsToRemove.isEmpty()) {
274 groupService.removeBucketsFromGroup(
275 deviceId,
276 groupKey,
277 new GroupBuckets(bucketsToRemove),
278 groupKey, appId);
279 }
280
281 List<GroupBucket> bucketsToAdd = new ArrayList<>(newBuckets);
282 bucketsToAdd.removeAll(oldBuckets);
283 if (!bucketsToAdd.isEmpty()) {
284 groupService.addBucketsToGroup(
285 deviceId,
286 groupKey,
287 new GroupBuckets(bucketsToAdd),
288 groupKey, appId);
289 }
290 }
291 }
292
293 /**
Hyunsun Moonc14be422016-04-27 15:06:56 -0500294 * Updates tenant service indirect access rules when VM is created or removed.
295 *
296 * @param host removed vm
297 * @param service tenant service
298 */
299 public void updateTenantServiceVm(Host host, CordService service) {
300 checkNotNull(host);
301 checkNotNull(service);
302
303 DeviceId deviceId = host.location().deviceId();
304 PortNumber inPort = host.location().port();
305
306 service.providerServices().stream().forEach(pServiceId -> {
307 Map<DeviceId, Set<PortNumber>> inPorts = Maps.newHashMap();
308 Map<DeviceId, GroupId> outGroups = Maps.newHashMap();
309
310 inPorts.put(deviceId, Sets.newHashSet(inPort));
311 outGroups.put(deviceId, getGroupId(pServiceId, deviceId));
312
313 populateInServiceRule(inPorts, outGroups, false);
314 });
315 }
316
317 /**
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800318 * Populates flow rules for management network access.
319 *
320 * @param host host which has management network interface
321 * @param mService management network service
322 */
323 public void populateManagementNetworkRules(Host host, CordService mService) {
324 checkNotNull(mService);
325
326 DeviceId deviceId = host.location().deviceId();
327 IpAddress hostIp = host.ipAddresses().stream().findFirst().get();
328
329 TrafficSelector selector = DefaultTrafficSelector.builder()
330 .matchEthType(Ethernet.TYPE_ARP)
331 .matchArpTpa(mService.serviceIp().getIp4Address())
332 .build();
333
334 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
335 .setOutput(PortNumber.LOCAL)
336 .build();
337
338 FlowRule flowRule = DefaultFlowRule.builder()
339 .fromApp(appId)
340 .withSelector(selector)
341 .withTreatment(treatment)
342 .withPriority(MANAGEMENT_PRIORITY)
343 .forDevice(deviceId)
344 .forTable(TABLE_FIRST)
345 .makePermanent()
346 .build();
347
348 processFlowRule(true, flowRule);
349
350 selector = DefaultTrafficSelector.builder()
351 .matchInPort(PortNumber.LOCAL)
352 .matchEthType(Ethernet.TYPE_ARP)
353 .matchArpTpa(hostIp.getIp4Address())
354 .build();
355
356 treatment = DefaultTrafficTreatment.builder()
357 .setOutput(host.location().port())
358 .build();
359
360 flowRule = DefaultFlowRule.builder()
361 .fromApp(appId)
362 .withSelector(selector)
363 .withTreatment(treatment)
364 .withPriority(MANAGEMENT_PRIORITY)
365 .forDevice(deviceId)
366 .forTable(TABLE_FIRST)
367 .makePermanent()
368 .build();
369
370 processFlowRule(true, flowRule);
371
372 selector = DefaultTrafficSelector.builder()
373 .matchInPort(PortNumber.LOCAL)
374 .matchEthType(Ethernet.TYPE_IPV4)
375 .matchIPDst(mService.serviceIpRange())
376 .build();
377
378 treatment = DefaultTrafficTreatment.builder()
379 .transition(TABLE_DST_IP)
380 .build();
381
382 flowRule = DefaultFlowRule.builder()
383 .fromApp(appId)
384 .withSelector(selector)
385 .withTreatment(treatment)
386 .withPriority(MANAGEMENT_PRIORITY)
387 .forDevice(deviceId)
388 .forTable(TABLE_FIRST)
389 .makePermanent()
390 .build();
391
392 processFlowRule(true, flowRule);
393
394 selector = DefaultTrafficSelector.builder()
395 .matchEthType(Ethernet.TYPE_IPV4)
396 .matchIPDst(mService.serviceIp().toIpPrefix())
397 .build();
398
399 treatment = DefaultTrafficTreatment.builder()
400 .setOutput(PortNumber.LOCAL)
401 .build();
402
403 flowRule = DefaultFlowRule.builder()
404 .fromApp(appId)
405 .withSelector(selector)
406 .withTreatment(treatment)
407 .withPriority(MANAGEMENT_PRIORITY)
408 .forDevice(deviceId)
409 .forTable(TABLE_ACCESS_TYPE)
410 .makePermanent()
411 .build();
412
413 processFlowRule(true, flowRule);
414 }
415
416 /**
Hyunsun Moon6d247342016-02-12 12:48:47 -0800417 * Populates rules for vSG VM.
418 *
419 * @param vSgHost vSG host
420 * @param vSgIps set of ip addresses of vSGs running inside the vSG VM
421 */
422 public void populateSubscriberGatewayRules(Host vSgHost, Set<IpAddress> vSgIps) {
423 VlanId serviceVlan = getServiceVlan(vSgHost);
424 PortNumber dpPort = getDpPort(vSgHost);
425
426 if (serviceVlan == null || dpPort == null) {
427 log.warn("Failed to populate rules for vSG VM {}", vSgHost.id());
428 return;
429 }
430
431 // for traffics with s-tag, strip the tag and take through the vSG VM
432 TrafficSelector selector = DefaultTrafficSelector.builder()
Hyunsun Moond5f6c3b2016-02-18 15:37:22 -0800433 .matchInPort(dpPort)
Hyunsun Moon6d247342016-02-12 12:48:47 -0800434 .matchVlanId(serviceVlan)
435 .build();
436
437 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Hyunsun Moon6d247342016-02-12 12:48:47 -0800438 .setOutput(vSgHost.location().port())
439 .build();
440
441 FlowRule flowRule = DefaultFlowRule.builder()
442 .fromApp(appId)
443 .withSelector(selector)
444 .withTreatment(treatment)
445 .withPriority(DEFAULT_PRIORITY)
446 .forDevice(vSgHost.location().deviceId())
447 .forTable(TABLE_Q_IN_Q)
448 .makePermanent()
449 .build();
450
451 processFlowRule(true, flowRule);
452
453 // for traffics with customer vlan, tag with the service vlan based on input port with
454 // lower priority to avoid conflict with WAN tag
455 selector = DefaultTrafficSelector.builder()
456 .matchInPort(vSgHost.location().port())
Hyunsun Moond5f6c3b2016-02-18 15:37:22 -0800457 .matchVlanId(serviceVlan)
Hyunsun Moon6d247342016-02-12 12:48:47 -0800458 .build();
459
460 treatment = DefaultTrafficTreatment.builder()
Hyunsun Moon6d247342016-02-12 12:48:47 -0800461 .setOutput(dpPort)
462 .build();
463
464 flowRule = DefaultFlowRule.builder()
465 .fromApp(appId)
466 .withSelector(selector)
467 .withTreatment(treatment)
Hyunsun Moond5f6c3b2016-02-18 15:37:22 -0800468 .withPriority(DEFAULT_PRIORITY)
Hyunsun Moon6d247342016-02-12 12:48:47 -0800469 .forDevice(vSgHost.location().deviceId())
470 .forTable(TABLE_Q_IN_Q)
471 .makePermanent()
472 .build();
473
474 processFlowRule(true, flowRule);
475
476 // for traffic coming from WAN, tag 500 and take through the vSG VM
477 // based on destination ip
478 vSgIps.stream().forEach(ip -> {
479 TrafficSelector downstream = DefaultTrafficSelector.builder()
480 .matchEthType(Ethernet.TYPE_IPV4)
481 .matchIPDst(ip.toIpPrefix())
482 .build();
483
484 TrafficTreatment downstreamTreatment = DefaultTrafficTreatment.builder()
485 .pushVlan()
486 .setVlanId(VLAN_WAN)
487 .setEthDst(vSgHost.mac())
488 .setOutput(vSgHost.location().port())
489 .build();
490
491 FlowRule downstreamFlowRule = DefaultFlowRule.builder()
492 .fromApp(appId)
493 .withSelector(downstream)
494 .withTreatment(downstreamTreatment)
495 .withPriority(DEFAULT_PRIORITY)
496 .forDevice(vSgHost.location().deviceId())
497 .forTable(TABLE_DST_IP)
498 .makePermanent()
499 .build();
500
501 processFlowRule(true, downstreamFlowRule);
502 });
503
504 // remove downstream flow rules for the vSG not shown in vSgIps
505 for (FlowRule rule : flowRuleService.getFlowRulesById(appId)) {
506 if (!rule.deviceId().equals(vSgHost.location().deviceId())) {
507 continue;
508 }
509 PortNumber output = getOutputFromTreatment(rule);
510 if (output == null || !output.equals(vSgHost.location().port()) ||
511 !isVlanPushFromTreatment(rule)) {
512 continue;
513 }
514
515 IpPrefix dstIp = getDstIpFromSelector(rule);
516 if (dstIp != null && !vSgIps.contains(dstIp.address())) {
517 processFlowRule(false, rule);
518 }
519 }
520 }
521
522 /**
Hyunsun Moon4a915152016-01-14 16:56:26 -0800523 * Populates default rules on the first table.
Hyunsun Moon133fd792016-02-09 01:55:48 -0800524 * It includes the rules for shuttling vxlan-encapped packets between ovs and
525 * linux stack,and external network connectivity.
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800526 *
527 * @param deviceId device id
Hyunsun Moon133fd792016-02-09 01:55:48 -0800528 * @param dpPort data plane interface port number
529 * @param dpIp data plane ip address
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800530 */
Hyunsun Moon133fd792016-02-09 01:55:48 -0800531 private void processFirstTable(DeviceId deviceId, PortNumber dpPort, IpAddress dpIp) {
Hyunsun Moon4a915152016-01-14 16:56:26 -0800532 // take vxlan packet out onto the physical port
533 TrafficSelector selector = DefaultTrafficSelector.builder()
534 .matchInPort(PortNumber.LOCAL)
535 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800536
Hyunsun Moon4a915152016-01-14 16:56:26 -0800537 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Hyunsun Moon133fd792016-02-09 01:55:48 -0800538 .setOutput(dpPort)
Hyunsun Moon4a915152016-01-14 16:56:26 -0800539 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800540
Hyunsun Moon4a915152016-01-14 16:56:26 -0800541 FlowRule flowRule = DefaultFlowRule.builder()
542 .fromApp(appId)
543 .withSelector(selector)
544 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800545 .withPriority(HIGH_PRIORITY)
Hyunsun Moon4a915152016-01-14 16:56:26 -0800546 .forDevice(deviceId)
547 .forTable(TABLE_FIRST)
548 .makePermanent()
549 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800550
Hyunsun Moon4a915152016-01-14 16:56:26 -0800551 processFlowRule(true, flowRule);
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800552
Hyunsun Moon4a915152016-01-14 16:56:26 -0800553 // take a vxlan encap'd packet through the Linux stack
554 selector = DefaultTrafficSelector.builder()
Hyunsun Moon133fd792016-02-09 01:55:48 -0800555 .matchInPort(dpPort)
Hyunsun Moon4a915152016-01-14 16:56:26 -0800556 .matchEthType(Ethernet.TYPE_IPV4)
557 .matchIPProtocol(IPv4.PROTOCOL_UDP)
558 .matchUdpDst(TpPort.tpPort(VXLAN_UDP_PORT))
559 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800560
Hyunsun Moon4a915152016-01-14 16:56:26 -0800561 treatment = DefaultTrafficTreatment.builder()
562 .setOutput(PortNumber.LOCAL)
563 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800564
Hyunsun Moon4a915152016-01-14 16:56:26 -0800565 flowRule = DefaultFlowRule.builder()
566 .fromApp(appId)
567 .withSelector(selector)
568 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800569 .withPriority(HIGH_PRIORITY)
Hyunsun Moon4a915152016-01-14 16:56:26 -0800570 .forDevice(deviceId)
571 .forTable(TABLE_FIRST)
572 .makePermanent()
573 .build();
574
575 processFlowRule(true, flowRule);
576
Hyunsun Moon133fd792016-02-09 01:55:48 -0800577 // take a packet to the data plane ip through Linux stack
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800578 selector = DefaultTrafficSelector.builder()
Hyunsun Moon133fd792016-02-09 01:55:48 -0800579 .matchInPort(dpPort)
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800580 .matchEthType(Ethernet.TYPE_IPV4)
Hyunsun Moon133fd792016-02-09 01:55:48 -0800581 .matchIPDst(dpIp.toIpPrefix())
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800582 .build();
583
584 treatment = DefaultTrafficTreatment.builder()
585 .setOutput(PortNumber.LOCAL)
586 .build();
587
588 flowRule = DefaultFlowRule.builder()
589 .fromApp(appId)
590 .withSelector(selector)
591 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800592 .withPriority(HIGH_PRIORITY)
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800593 .forDevice(deviceId)
594 .forTable(TABLE_FIRST)
595 .makePermanent()
596 .build();
597
598 processFlowRule(true, flowRule);
599
600 // take an arp packet from physical through Linux stack
601 selector = DefaultTrafficSelector.builder()
Hyunsun Moon133fd792016-02-09 01:55:48 -0800602 .matchInPort(dpPort)
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800603 .matchEthType(Ethernet.TYPE_ARP)
Hyunsun Moon6d247342016-02-12 12:48:47 -0800604 .matchArpTpa(dpIp.getIp4Address())
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800605 .build();
606
607 treatment = DefaultTrafficTreatment.builder()
608 .setOutput(PortNumber.LOCAL)
609 .build();
610
611 flowRule = DefaultFlowRule.builder()
612 .fromApp(appId)
613 .withSelector(selector)
614 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800615 .withPriority(HIGH_PRIORITY)
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800616 .forDevice(deviceId)
617 .forTable(TABLE_FIRST)
618 .makePermanent()
619 .build();
620
621 processFlowRule(true, flowRule);
622
Hyunsun Moon4a915152016-01-14 16:56:26 -0800623 // take all else to the next table
624 selector = DefaultTrafficSelector.builder()
625 .build();
626
627 treatment = DefaultTrafficTreatment.builder()
628 .transition(TABLE_IN_PORT)
629 .build();
630
631 flowRule = DefaultFlowRule.builder()
632 .fromApp(appId)
633 .withSelector(selector)
634 .withTreatment(treatment)
635 .withPriority(LOWEST_PRIORITY)
636 .forDevice(deviceId)
637 .forTable(TABLE_FIRST)
638 .makePermanent()
639 .build();
640
641 processFlowRule(true, flowRule);
Hyunsun Moon6d247342016-02-12 12:48:47 -0800642
643 // take all vlan tagged packet to the Q_IN_Q table
644 selector = DefaultTrafficSelector.builder()
645 .matchVlanId(VlanId.ANY)
646 .build();
647
648 treatment = DefaultTrafficTreatment.builder()
649 .transition(TABLE_Q_IN_Q)
650 .build();
651
652 flowRule = DefaultFlowRule.builder()
653 .fromApp(appId)
654 .withSelector(selector)
655 .withTreatment(treatment)
656 .withPriority(VSG_PRIORITY)
657 .forDevice(deviceId)
658 .forTable(TABLE_FIRST)
659 .makePermanent()
660 .build();
661
662 processFlowRule(true, flowRule);
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800663 }
664
665 /**
Hyunsun Moon133fd792016-02-09 01:55:48 -0800666 * Forward table miss packets in ACCESS_TYPE table to data plane port.
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800667 *
668 * @param deviceId device id
Hyunsun Moon133fd792016-02-09 01:55:48 -0800669 * @param dpPort data plane interface port number
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800670 */
Hyunsun Moon133fd792016-02-09 01:55:48 -0800671 private void processAccessTypeTable(DeviceId deviceId, PortNumber dpPort) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800672 TrafficSelector selector = DefaultTrafficSelector.builder()
673 .build();
674
675 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Hyunsun Moon133fd792016-02-09 01:55:48 -0800676 .setOutput(dpPort)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800677 .build();
678
679 FlowRule flowRule = DefaultFlowRule.builder()
680 .fromApp(appId)
681 .withSelector(selector)
682 .withTreatment(treatment)
683 .withPriority(LOWEST_PRIORITY)
684 .forDevice(deviceId)
685 .forTable(TABLE_ACCESS_TYPE)
686 .makePermanent()
687 .build();
688
689 processFlowRule(true, flowRule);
690 }
691
692 /**
Hyunsun Moon4a915152016-01-14 16:56:26 -0800693 * Populates default rules for IN_PORT table.
694 * All packets from tunnel port are forwarded to TUNNEL_ID table and all packets
Hyunsun Moon133fd792016-02-09 01:55:48 -0800695 * from data plane interface port to ACCESS_TYPE table.
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800696 *
697 * @param deviceId device id to install the rules
Hyunsun Moon4a915152016-01-14 16:56:26 -0800698 * @param tunnelPort tunnel port number
Hyunsun Moon133fd792016-02-09 01:55:48 -0800699 * @param dpPort data plane interface port number
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800700 */
Hyunsun Moon133fd792016-02-09 01:55:48 -0800701 private void processInPortTable(DeviceId deviceId, PortNumber tunnelPort, PortNumber dpPort) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800702 checkNotNull(tunnelPort);
703
704 TrafficSelector selector = DefaultTrafficSelector.builder()
705 .matchInPort(tunnelPort)
706 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800707
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800708 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
709 .transition(TABLE_TUNNEL_IN)
710 .build();
711
712 FlowRule flowRule = DefaultFlowRule.builder()
713 .fromApp(appId)
714 .withSelector(selector)
715 .withTreatment(treatment)
716 .withPriority(DEFAULT_PRIORITY)
717 .forDevice(deviceId)
718 .forTable(TABLE_IN_PORT)
719 .makePermanent()
720 .build();
721
722 processFlowRule(true, flowRule);
Hyunsun Moon4a915152016-01-14 16:56:26 -0800723
724 selector = DefaultTrafficSelector.builder()
Hyunsun Moon133fd792016-02-09 01:55:48 -0800725 .matchInPort(dpPort)
Hyunsun Moon4a915152016-01-14 16:56:26 -0800726 .build();
727
728 treatment = DefaultTrafficTreatment.builder()
729 .transition(TABLE_DST_IP)
730 .build();
731
732 flowRule = DefaultFlowRule.builder()
733 .fromApp(appId)
734 .withSelector(selector)
735 .withTreatment(treatment)
736 .withPriority(DEFAULT_PRIORITY)
737 .forDevice(deviceId)
738 .forTable(TABLE_IN_PORT)
739 .makePermanent()
740 .build();
741
742 processFlowRule(true, flowRule);
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800743 }
744
745 /**
Hyunsun Moon6d247342016-02-12 12:48:47 -0800746 * Populates default rules for Q_IN_Q table.
747 *
748 * @param deviceId device id
749 * @param dpPort data plane interface port number
750 */
751 private void processQInQTable(DeviceId deviceId, PortNumber dpPort) {
752 // for traffic going out to WAN, strip vid 500 and take through data plane interface
753 TrafficSelector selector = DefaultTrafficSelector.builder()
754 .matchVlanId(VLAN_WAN)
755 .build();
756
757 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
758 .popVlan()
759 .setOutput(dpPort)
760 .build();
761
762 FlowRule flowRule = DefaultFlowRule.builder()
763 .fromApp(appId)
764 .withSelector(selector)
765 .withTreatment(treatment)
766 .withPriority(DEFAULT_PRIORITY)
767 .forDevice(deviceId)
768 .forTable(TABLE_Q_IN_Q)
769 .makePermanent()
770 .build();
771
772 processFlowRule(true, flowRule);
773
774 selector = DefaultTrafficSelector.builder()
775 .matchVlanId(VLAN_WAN)
776 .matchEthType(Ethernet.TYPE_ARP)
777 .build();
778
779 treatment = DefaultTrafficTreatment.builder()
780 .setOutput(PortNumber.CONTROLLER)
781 .build();
782
783 flowRule = DefaultFlowRule.builder()
784 .fromApp(appId)
785 .withSelector(selector)
786 .withTreatment(treatment)
787 .withPriority(HIGH_PRIORITY)
788 .forDevice(deviceId)
789 .forTable(TABLE_Q_IN_Q)
790 .makePermanent()
791 .build();
792
793 processFlowRule(true, flowRule);
794 }
795
796 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800797 * Populates rules for local in port in IN_PORT table.
798 * Flows from a given in port, whose source IP is service IP transition
799 * to DST_TYPE table. Other flows transition to IN_SERVICE table.
800 *
801 * @param deviceId device id to install the rules
802 * @param inPort in port
803 * @param srcIp source ip
Hyunsun Moonc14be422016-04-27 15:06:56 -0500804 * @param install true to install or false to remove
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800805 */
Hyunsun Moonc14be422016-04-27 15:06:56 -0500806 private void populateLocalInPortRule(DeviceId deviceId, PortNumber inPort, IpAddress srcIp,
807 boolean install) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800808 TrafficSelector selector = DefaultTrafficSelector.builder()
809 .matchInPort(inPort)
810 .matchEthType(Ethernet.TYPE_IPV4)
811 .matchIPSrc(srcIp.toIpPrefix())
812 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800813
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800814 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
815 .transition(TABLE_ACCESS_TYPE)
816 .build();
817
818
819 FlowRule flowRule = DefaultFlowRule.builder()
820 .fromApp(appId)
821 .withSelector(selector)
822 .withTreatment(treatment)
823 .withPriority(DEFAULT_PRIORITY)
824 .forDevice(deviceId)
825 .forTable(TABLE_IN_PORT)
826 .makePermanent()
827 .build();
828
Hyunsun Moonc14be422016-04-27 15:06:56 -0500829 processFlowRule(install, flowRule);
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800830
831 selector = DefaultTrafficSelector.builder()
832 .matchInPort(inPort)
833 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800834
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800835 treatment = DefaultTrafficTreatment.builder()
836 .transition(TABLE_IN_SERVICE)
837 .build();
838
839 flowRule = DefaultFlowRule.builder()
840 .fromApp(appId)
841 .withSelector(selector)
842 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800843 .withPriority(LOW_PRIORITY)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800844 .forDevice(deviceId)
845 .forTable(TABLE_IN_PORT)
846 .makePermanent()
847 .build();
848
Hyunsun Moonc14be422016-04-27 15:06:56 -0500849 processFlowRule(install, flowRule);
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800850 }
851
852 /**
853 * Populates direct VM access rules for ACCESS_TYPE table.
854 * These rules are installed to all devices.
855 *
856 * @param srcRange source ip range
857 * @param dstRange destination ip range
Hyunsun Moonc14be422016-04-27 15:06:56 -0500858 * @param install true to install or false to remove
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800859 */
Hyunsun Moonc14be422016-04-27 15:06:56 -0500860 private void populateDirectAccessRule(Ip4Prefix srcRange, Ip4Prefix dstRange, boolean install) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800861 TrafficSelector selector = DefaultTrafficSelector.builder()
862 .matchEthType(Ethernet.TYPE_IPV4)
863 .matchIPSrc(srcRange)
864 .matchIPDst(dstRange)
865 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800866
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800867 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
868 .transition(TABLE_DST_IP)
869 .build();
870
Hyunsun Moon98025542016-03-08 04:36:02 -0800871
Hyunsun Moonfae776d2016-03-08 18:07:52 -0800872 getVirtualSwitches().stream().forEach(deviceId -> {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800873 FlowRule flowRuleDirect = DefaultFlowRule.builder()
874 .fromApp(appId)
875 .withSelector(selector)
876 .withTreatment(treatment)
Hyunsun Moon81ab23b2016-02-01 23:00:56 -0800877 .withPriority(DEFAULT_PRIORITY)
Hyunsun Moonfae776d2016-03-08 18:07:52 -0800878 .forDevice(deviceId)
Hyunsun Moon81ab23b2016-02-01 23:00:56 -0800879 .forTable(TABLE_ACCESS_TYPE)
880 .makePermanent()
881 .build();
882
Hyunsun Moonc14be422016-04-27 15:06:56 -0500883 processFlowRule(install, flowRuleDirect);
Hyunsun Moonfae776d2016-03-08 18:07:52 -0800884 });
Hyunsun Moon81ab23b2016-02-01 23:00:56 -0800885 }
886
887 /**
888 * Populates drop rules that does not match any direct access rules but has
889 * destination to a different service network in ACCESS_TYPE table.
890 *
891 * @param dstRange destination ip range
Hyunsun Moonc14be422016-04-27 15:06:56 -0500892 * @param install true to install or false to remove
Hyunsun Moon81ab23b2016-02-01 23:00:56 -0800893 */
Hyunsun Moonc14be422016-04-27 15:06:56 -0500894 private void populateServiceIsolationRule(Ip4Prefix dstRange, boolean install) {
Hyunsun Moon81ab23b2016-02-01 23:00:56 -0800895 TrafficSelector selector = DefaultTrafficSelector.builder()
896 .matchEthType(Ethernet.TYPE_IPV4)
897 .matchIPDst(dstRange)
898 .build();
899
900 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
901 .drop()
902 .build();
903
Hyunsun Moonfae776d2016-03-08 18:07:52 -0800904 getVirtualSwitches().stream().forEach(deviceId -> {
Hyunsun Moon81ab23b2016-02-01 23:00:56 -0800905 FlowRule flowRuleDirect = DefaultFlowRule.builder()
906 .fromApp(appId)
907 .withSelector(selector)
908 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800909 .withPriority(LOW_PRIORITY)
Hyunsun Moonfae776d2016-03-08 18:07:52 -0800910 .forDevice(deviceId)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800911 .forTable(TABLE_ACCESS_TYPE)
912 .makePermanent()
913 .build();
914
Hyunsun Moonc14be422016-04-27 15:06:56 -0500915 processFlowRule(install, flowRuleDirect);
Hyunsun Moonfae776d2016-03-08 18:07:52 -0800916 });
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800917 }
918
919 /**
920 * Populates indirect service access rules for ACCESS_TYPE table.
921 * These rules are installed to all devices.
922 *
923 * @param srcRange source range
924 * @param serviceIp service ip
925 * @param outGroups list of output group
Hyunsun Moonc14be422016-04-27 15:06:56 -0500926 * @param install true to install or false to remove
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800927 */
928 private void populateIndirectAccessRule(Ip4Prefix srcRange, Ip4Address serviceIp,
Hyunsun Moonc14be422016-04-27 15:06:56 -0500929 Map<DeviceId, GroupId> outGroups, boolean install) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800930 TrafficSelector selector = DefaultTrafficSelector.builder()
931 .matchEthType(Ethernet.TYPE_IPV4)
932 .matchIPSrc(srcRange)
933 .matchIPDst(serviceIp.toIpPrefix())
934 .build();
935
936 for (Map.Entry<DeviceId, GroupId> outGroup : outGroups.entrySet()) {
937 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
938 .group(outGroup.getValue())
939 .build();
940
941 FlowRule flowRule = DefaultFlowRule.builder()
942 .fromApp(appId)
943 .withSelector(selector)
944 .withTreatment(treatment)
Hyunsun Moon81ab23b2016-02-01 23:00:56 -0800945 .withPriority(HIGH_PRIORITY)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800946 .forDevice(outGroup.getKey())
947 .forTable(TABLE_ACCESS_TYPE)
948 .makePermanent()
949 .build();
950
Hyunsun Moonc14be422016-04-27 15:06:56 -0500951 processFlowRule(install, flowRule);
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800952 }
953 }
954
955 /**
956 * Populates flow rules for IN_SERVICE table.
957 *
958 * @param inPorts list of inports related to the service for each device
959 * @param outGroups set of output groups
Hyunsun Moonc14be422016-04-27 15:06:56 -0500960 * @param install true to install or false to remove
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800961 */
Hyunsun Moonc14be422016-04-27 15:06:56 -0500962 private void populateInServiceRule(Map<DeviceId, Set<PortNumber>> inPorts,
963 Map<DeviceId, GroupId> outGroups, boolean install) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800964 checkNotNull(inPorts);
965 checkNotNull(outGroups);
966
967 for (Map.Entry<DeviceId, Set<PortNumber>> entry : inPorts.entrySet()) {
968 Set<PortNumber> ports = entry.getValue();
969 DeviceId deviceId = entry.getKey();
970
971 GroupId groupId = outGroups.get(deviceId);
972 if (groupId == null) {
973 continue;
974 }
975
976 ports.stream().forEach(port -> {
977 TrafficSelector selector = DefaultTrafficSelector.builder()
978 .matchInPort(port)
979 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800980
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800981 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
982 .group(groupId)
983 .build();
984
985 FlowRule flowRule = DefaultFlowRule.builder()
986 .fromApp(appId)
987 .withSelector(selector)
988 .withTreatment(treatment)
989 .withPriority(DEFAULT_PRIORITY)
990 .forDevice(deviceId)
991 .forTable(TABLE_IN_SERVICE)
992 .makePermanent()
993 .build();
994
Hyunsun Moonc14be422016-04-27 15:06:56 -0500995 processFlowRule(install, flowRule);
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800996 });
997 }
998 }
999
1000 /**
1001 * Populates flow rules for DST_IP table.
1002 *
1003 * @param deviceId device id
1004 * @param inPort in port
1005 * @param dstMac mac address
1006 * @param dstIp destination ip
1007 * @param tunnelId tunnel id
1008 * @param tunnelIp tunnel remote ip
Hyunsun Moonc14be422016-04-27 15:06:56 -05001009 * @param install true to install or false to remove
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001010 */
1011 private void populateDstIpRule(DeviceId deviceId, PortNumber inPort, MacAddress dstMac,
Hyunsun Moonc14be422016-04-27 15:06:56 -05001012 IpAddress dstIp, long tunnelId, IpAddress tunnelIp,
1013 boolean install) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001014 TrafficSelector selector = DefaultTrafficSelector.builder()
1015 .matchEthType(Ethernet.TYPE_IPV4)
1016 .matchIPDst(dstIp.toIpPrefix())
1017 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -08001018
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001019 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
1020 .setEthDst(dstMac)
1021 .setOutput(inPort)
1022 .build();
1023
1024 FlowRule flowRule = DefaultFlowRule.builder()
1025 .fromApp(appId)
1026 .withSelector(selector)
1027 .withTreatment(treatment)
1028 .withPriority(DEFAULT_PRIORITY)
1029 .forDevice(deviceId)
1030 .forTable(TABLE_DST_IP)
1031 .makePermanent()
1032 .build();
1033
Hyunsun Moonc14be422016-04-27 15:06:56 -05001034 processFlowRule(install, flowRule);
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001035
Hyunsun Moonfae776d2016-03-08 18:07:52 -08001036 for (DeviceId vSwitchId : getVirtualSwitches()) {
1037 if (vSwitchId.equals(deviceId)) {
Hyunsun Moon98025542016-03-08 04:36:02 -08001038 continue;
1039 }
1040
Hyunsun Moonfae776d2016-03-08 18:07:52 -08001041 ExtensionTreatment tunnelDst = getTunnelDst(vSwitchId, tunnelIp.getIp4Address());
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001042 if (tunnelDst == null) {
1043 continue;
1044 }
1045
1046 treatment = DefaultTrafficTreatment.builder()
1047 .setEthDst(dstMac)
1048 .setTunnelId(tunnelId)
Hyunsun Moonfae776d2016-03-08 18:07:52 -08001049 .extension(tunnelDst, vSwitchId)
1050 .setOutput(getTunnelPort(vSwitchId))
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001051 .build();
1052
1053 flowRule = DefaultFlowRule.builder()
1054 .fromApp(appId)
1055 .withSelector(selector)
1056 .withTreatment(treatment)
1057 .withPriority(DEFAULT_PRIORITY)
Hyunsun Moonfae776d2016-03-08 18:07:52 -08001058 .forDevice(vSwitchId)
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001059 .forTable(TABLE_DST_IP)
1060 .makePermanent()
1061 .build();
1062
Hyunsun Moonc14be422016-04-27 15:06:56 -05001063 processFlowRule(install, flowRule);
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001064 }
1065 }
1066
1067 /**
1068 * Populates flow rules for TUNNEL_ID table.
1069 *
1070 * @param deviceId device id
1071 * @param inPort in port
1072 * @param mac mac address
1073 * @param tunnelId tunnel id
Hyunsun Moonc14be422016-04-27 15:06:56 -05001074 * @param install true to install or false to remove
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001075 */
Hyunsun Moonc14be422016-04-27 15:06:56 -05001076 private void populateTunnelInRule(DeviceId deviceId, PortNumber inPort, MacAddress mac,
1077 long tunnelId, boolean install) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001078 TrafficSelector selector = DefaultTrafficSelector.builder()
1079 .matchTunnelId(tunnelId)
1080 .matchEthDst(mac)
1081 .build();
1082
1083 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
1084 .setOutput(inPort)
1085 .build();
1086
1087 FlowRule flowRule = DefaultFlowRule.builder()
1088 .fromApp(appId)
1089 .withSelector(selector)
1090 .withTreatment(treatment)
1091 .withPriority(DEFAULT_PRIORITY)
1092 .forDevice(deviceId)
1093 .forTable(TABLE_TUNNEL_IN)
1094 .makePermanent()
1095 .build();
1096
Hyunsun Moonc14be422016-04-27 15:06:56 -05001097 processFlowRule(install, flowRule);
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001098 }
1099
1100 /**
1101 * Installs or uninstall a given rule.
1102 *
1103 * @param install true to install, false to uninstall
1104 * @param rule rule
1105 */
1106 private void processFlowRule(boolean install, FlowRule rule) {
1107 FlowRuleOperations.Builder oBuilder = FlowRuleOperations.builder();
1108 oBuilder = install ? oBuilder.add(rule) : oBuilder.remove(rule);
1109
1110 flowRuleService.apply(oBuilder.build(new FlowRuleOperationsContext() {
1111 @Override
1112 public void onError(FlowRuleOperations ops) {
1113 log.error(String.format("Failed %s, %s", ops.toString(), rule.toString()));
1114 }
1115 }));
1116 }
1117
1118 /**
1119 * Returns tunnel port of the device.
1120 *
1121 * @param deviceId device id
1122 * @return tunnel port number, or null if no tunnel port exists on a given device
1123 */
1124 private PortNumber getTunnelPort(DeviceId deviceId) {
Hyunsun Moon5a4346f2016-01-15 11:41:14 -08001125 Port port = deviceService.getPorts(deviceId).stream()
Hyunsun Moon6d247342016-02-12 12:48:47 -08001126 .filter(p -> p.annotations().value(PORT_NAME).contains(tunnelType))
1127 .findFirst().orElse(null);
Hyunsun Moon5a4346f2016-01-15 11:41:14 -08001128
1129 return port == null ? null : port.number();
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001130 }
1131
1132 /**
Hyunsun Moon133fd792016-02-09 01:55:48 -08001133 * Returns data plane interface port name of a given device.
Hyunsun Moon4a915152016-01-14 16:56:26 -08001134 *
1135 * @param deviceId device id
Hyunsun Moon133fd792016-02-09 01:55:48 -08001136 * @param dpIntf data plane interface port name
1137 * @return data plane interface port number, or null if no such port exists
Hyunsun Moon4a915152016-01-14 16:56:26 -08001138 */
Hyunsun Moon133fd792016-02-09 01:55:48 -08001139 private PortNumber getDpPort(DeviceId deviceId, String dpIntf) {
Hyunsun Moon5a4346f2016-01-15 11:41:14 -08001140 Port port = deviceService.getPorts(deviceId).stream()
Hyunsun Moon6d247342016-02-12 12:48:47 -08001141 .filter(p -> p.annotations().value(PORT_NAME).contains(dpIntf) &&
1142 p.isEnabled())
1143 .findFirst().orElse(null);
Hyunsun Moon5a4346f2016-01-15 11:41:14 -08001144
1145 return port == null ? null : port.number();
Hyunsun Moon4a915152016-01-14 16:56:26 -08001146 }
1147
Hyunsun Moon6d247342016-02-12 12:48:47 -08001148 /** Returns data plane interface port number of a given host.
1149 *
1150 * @param host host
1151 * @return port number, or null
1152 */
1153 private PortNumber getDpPort(Host host) {
1154 String portName = host.annotations().value(DATA_PLANE_INTF);
1155 return portName == null ? null : getDpPort(host.location().deviceId(), portName);
1156 }
1157
1158 /**
1159 * Returns service vlan from a given host.
1160 *
1161 * @param host host
1162 * @return vlan id, or null
1163 */
1164 private VlanId getServiceVlan(Host host) {
1165 String serviceVlan = host.annotations().value(S_TAG);
1166 return serviceVlan == null ? null : VlanId.vlanId(Short.parseShort(serviceVlan));
1167 }
1168
Hyunsun Moon4a915152016-01-14 16:56:26 -08001169 /**
Hyunsun Moonc14be422016-04-27 15:06:56 -05001170 * Returns IP address for tunneling for a given host.
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001171 *
Hyunsun Moonc14be422016-04-27 15:06:56 -05001172 * @param host host
1173 * @return ip address, or null
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001174 */
Hyunsun Moonc14be422016-04-27 15:06:56 -05001175 private IpAddress getTunnelIp(Host host) {
1176 String ip = host.annotations().value(DATA_PLANE_IP);
1177 return ip == null ? null : IpAddress.valueOf(ip);
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001178 }
1179
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001180
1181 /**
1182 * Returns the destination IP from a given flow rule if the rule contains
1183 * the match of it.
1184 *
1185 * @param flowRule flow rule
1186 * @return ip prefix, or null if the rule doesn't have ip match
1187 */
1188 private IpPrefix getDstIpFromSelector(FlowRule flowRule) {
1189 Criterion criterion = flowRule.selector().getCriterion(IPV4_DST);
1190 if (criterion != null && criterion instanceof IPCriterion) {
1191 IPCriterion ip = (IPCriterion) criterion;
1192 return ip.ip();
1193 } else {
1194 return null;
1195 }
1196 }
1197
1198 /**
Hyunsun Moond52bffc2016-01-29 18:57:05 -08001199 * Returns the output port number from a given flow rule.
1200 *
1201 * @param flowRule flow rule
1202 * @return port number, or null if the rule does not have output instruction
1203 */
1204 private PortNumber getOutputFromTreatment(FlowRule flowRule) {
1205 Instruction instruction = flowRule.treatment().allInstructions().stream()
Hyunsun Moon6d247342016-02-12 12:48:47 -08001206 .filter(inst -> inst instanceof Instructions.OutputInstruction)
Hyunsun Moond52bffc2016-01-29 18:57:05 -08001207 .findFirst()
1208 .orElse(null);
1209
1210 if (instruction == null) {
1211 return null;
1212 }
1213
1214 return ((Instructions.OutputInstruction) instruction).port();
1215 }
1216
1217 /**
Hyunsun Moon6d247342016-02-12 12:48:47 -08001218 * Returns if a given flow rule has vlan push instruction or not.
1219 *
1220 * @param flowRule flow rule
1221 * @return true if it includes vlan push, or false
1222 */
1223 private boolean isVlanPushFromTreatment(FlowRule flowRule) {
1224 Instruction instruction = flowRule.treatment().allInstructions().stream()
1225 .filter(inst -> inst instanceof L2ModificationInstruction)
1226 .filter(inst -> ((L2ModificationInstruction) inst).subtype().equals(VLAN_PUSH))
1227 .findAny()
1228 .orElse(null);
1229
1230 return instruction != null;
1231 }
1232
1233 /**
Hyunsun Moon4a915152016-01-14 16:56:26 -08001234 * Creates a new group for a given service.
1235 *
1236 * @param deviceId device id to create a group
1237 * @param service cord service
1238 * @return group id, or null if it fails to create
1239 */
1240 private GroupId createServiceGroup(DeviceId deviceId, CordService service) {
1241 checkNotNull(service);
1242
1243 GroupKey groupKey = getGroupKey(service.id());
1244 Group group = groupService.getGroup(deviceId, groupKey);
1245 GroupId groupId = getGroupId(service.id(), deviceId);
1246
1247 if (group != null) {
1248 log.debug("Group {} is already exist in {}", service.id(), deviceId);
1249 return groupId;
1250 }
1251
Hyunsun Moonc14be422016-04-27 15:06:56 -05001252 GroupBuckets buckets = getServiceGroupBuckets(
1253 deviceId, service.segmentationId(), service.hosts());
Hyunsun Moon4a915152016-01-14 16:56:26 -08001254 GroupDescription groupDescription = new DefaultGroupDescription(
1255 deviceId,
1256 GroupDescription.Type.SELECT,
1257 buckets,
1258 groupKey,
1259 groupId.id(),
1260 appId);
1261
1262 groupService.addGroup(groupDescription);
1263
1264 return groupId;
1265 }
1266
1267 /**
1268 * Returns group buckets for a given device.
1269 *
1270 * @param deviceId device id
1271 * @param tunnelId tunnel id
1272 * @param hosts list of host
1273 * @return group buckets
1274 */
Hyunsun Moonc14be422016-04-27 15:06:56 -05001275 private GroupBuckets getServiceGroupBuckets(DeviceId deviceId, long tunnelId,
1276 Map<Host, IpAddress> hosts) {
Hyunsun Moon4a915152016-01-14 16:56:26 -08001277 List<GroupBucket> buckets = Lists.newArrayList();
1278
1279 for (Map.Entry<Host, IpAddress> entry : hosts.entrySet()) {
1280 Host host = entry.getKey();
1281 Ip4Address remoteIp = entry.getValue().getIp4Address();
1282 DeviceId hostDevice = host.location().deviceId();
1283
1284 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
1285 .builder()
1286 .setEthDst(host.mac());
1287
1288 if (deviceId.equals(hostDevice)) {
1289 tBuilder.setOutput(host.location().port());
1290 } else {
1291 ExtensionTreatment tunnelDst = getTunnelDst(deviceId, remoteIp);
1292 if (tunnelDst == null) {
1293 continue;
1294 }
1295
1296 tBuilder.extension(tunnelDst, deviceId)
1297 .setTunnelId(tunnelId)
1298 .setOutput(getTunnelPort(hostDevice));
1299 }
1300
1301 buckets.add(DefaultGroupBucket.createSelectGroupBucket(tBuilder.build()));
1302 }
1303
1304 return new GroupBuckets(buckets);
1305 }
1306
1307 /**
1308 * Returns globally unique group ID.
1309 *
1310 * @param serviceId service id
1311 * @param deviceId device id
1312 * @return group id
1313 */
1314 private GroupId getGroupId(CordServiceId serviceId, DeviceId deviceId) {
1315 return new DefaultGroupId(Objects.hash(serviceId, deviceId));
1316 }
1317
1318 /**
1319 * Returns group key of a service.
1320 *
1321 * @param serviceId service id
1322 * @return group key
1323 */
1324 private GroupKey getGroupKey(CordServiceId serviceId) {
1325 return new DefaultGroupKey(serviceId.id().getBytes());
1326 }
1327
1328 /**
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001329 * Returns extension instruction to set tunnel destination.
1330 *
1331 * @param deviceId device id
1332 * @param remoteIp tunnel destination address
1333 * @return extension treatment or null if it fails to get instruction
1334 */
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001335 private ExtensionTreatment getTunnelDst(DeviceId deviceId, Ip4Address remoteIp) {
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001336 try {
Jian Li7532eb12016-04-15 13:22:05 -07001337 Device device = deviceService.getDevice(deviceId);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001338
Jian Li7532eb12016-04-15 13:22:05 -07001339 if (device.is(ExtensionTreatmentResolver.class)) {
1340 ExtensionTreatmentResolver resolver = device.as(ExtensionTreatmentResolver.class);
1341 ExtensionTreatment treatment =
1342 resolver.getExtensionInstruction(NICIRA_SET_TUNNEL_DST.type());
1343 treatment.setPropertyValue("tunnelDst", remoteIp);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001344
Jian Li7532eb12016-04-15 13:22:05 -07001345 return treatment;
1346 } else {
1347 log.warn("The extension treatment resolving behaviour is not supported in device {}",
1348 device.id().toString());
1349 return null;
1350 }
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001351 } catch (ItemNotFoundException | UnsupportedOperationException |
1352 ExtensionPropertyException e) {
1353 log.error("Failed to get extension instruction {}", deviceId);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001354 return null;
1355 }
1356 }
Hyunsun Moonfae776d2016-03-08 18:07:52 -08001357
1358 /**
1359 * Returns integration bridges configured in the system.
1360 *
1361 * @return set of device ids
1362 */
1363 private Set<DeviceId> getVirtualSwitches() {
1364 CordVtnConfig config = configRegistry.getConfig(appId, CordVtnConfig.class);
1365 if (config == null) {
1366 log.debug("No configuration found for {}", appId.name());
1367 return Sets.newHashSet();
1368 }
1369
1370 return config.cordVtnNodes().stream()
1371 .map(CordVtnNode::intBrId).collect(Collectors.toSet());
1372 }
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001373}
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001374