blob: f6c23b4978a86f7ba6e83860bb08e76db349f381 [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 Moon6d247342016-02-12 12:48:47 -080028import org.onlab.packet.VlanId;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080029import org.onlab.util.ItemNotFoundException;
30import org.onosproject.core.ApplicationId;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080031import org.onosproject.core.DefaultGroupId;
32import org.onosproject.core.GroupId;
33import org.onosproject.mastership.MastershipService;
34import org.onosproject.net.Device;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080035import org.onosproject.net.DeviceId;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080036import org.onosproject.net.Host;
Hyunsun Moon5a4346f2016-01-15 11:41:14 -080037import org.onosproject.net.Port;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080038import org.onosproject.net.PortNumber;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080039import org.onosproject.net.behaviour.ExtensionTreatmentResolver;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080040import org.onosproject.net.device.DeviceService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080041import org.onosproject.net.driver.DefaultDriverData;
42import org.onosproject.net.driver.DefaultDriverHandler;
43import org.onosproject.net.driver.Driver;
44import org.onosproject.net.driver.DriverHandler;
45import org.onosproject.net.driver.DriverService;
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;
56import org.onosproject.net.flow.criteria.EthCriterion;
57import org.onosproject.net.flow.criteria.IPCriterion;
58import org.onosproject.net.flow.criteria.PortCriterion;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080059import org.onosproject.net.flow.instructions.ExtensionPropertyException;
60import org.onosproject.net.flow.instructions.ExtensionTreatment;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080061import org.onosproject.net.flow.instructions.Instruction;
62import org.onosproject.net.flow.instructions.Instructions;
Hyunsun Moon6d247342016-02-12 12:48:47 -080063import org.onosproject.net.flow.instructions.L2ModificationInstruction;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080064import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
65import org.onosproject.net.group.DefaultGroupBucket;
66import org.onosproject.net.group.DefaultGroupDescription;
67import org.onosproject.net.group.DefaultGroupKey;
68import org.onosproject.net.group.Group;
69import org.onosproject.net.group.GroupBucket;
70import org.onosproject.net.group.GroupBuckets;
71import org.onosproject.net.group.GroupDescription;
72import org.onosproject.net.group.GroupKey;
73import org.onosproject.net.group.GroupService;
sangho0c2a3da2016-02-16 13:39:07 +090074import org.onosproject.openstacknetworking.OpenstackNetwork;
75import org.onosproject.openstacknetworking.OpenstackSubnet;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080076import org.slf4j.Logger;
77
Hyunsun Moon4161e6f2016-01-07 01:32:31 -080078import java.util.ArrayList;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080079import java.util.List;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080080import java.util.Map;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080081import java.util.Objects;
82import java.util.Set;
83import java.util.stream.Collectors;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080084
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080085import static com.google.common.base.Preconditions.checkNotNull;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080086import static org.onosproject.net.Device.Type.SWITCH;
87import static org.onosproject.net.flow.criteria.Criterion.Type.IN_PORT;
88import static org.onosproject.net.flow.criteria.Criterion.Type.IPV4_DST;
89import static org.onosproject.net.flow.criteria.Criterion.Type.IPV4_SRC;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080090import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080091import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.ETH_DST;
Hyunsun Moon6d247342016-02-12 12:48:47 -080092import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.VLAN_PUSH;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080093import static org.slf4j.LoggerFactory.getLogger;
94
95/**
Hyunsun Moonc71231d2015-12-16 20:53:23 -080096 * Populates rules for CORD VTN service.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080097 */
Hyunsun Moonc71231d2015-12-16 20:53:23 -080098public class CordVtnRuleInstaller {
99
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800100 protected final Logger log = getLogger(getClass());
101
Hyunsun Moon4a915152016-01-14 16:56:26 -0800102 private static final int TABLE_FIRST = 0;
103 private static final int TABLE_IN_PORT = 1;
104 private static final int TABLE_ACCESS_TYPE = 2;
105 private static final int TABLE_IN_SERVICE = 3;
106 private static final int TABLE_DST_IP = 4;
107 private static final int TABLE_TUNNEL_IN = 5;
Hyunsun Moon6d247342016-02-12 12:48:47 -0800108 private static final int TABLE_Q_IN_Q = 6;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800109
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800110 private static final int MANAGEMENT_PRIORITY = 55000;
Hyunsun Moon6d247342016-02-12 12:48:47 -0800111 private static final int VSG_PRIORITY = 55000;
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800112 private static final int HIGH_PRIORITY = 50000;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800113 private static final int DEFAULT_PRIORITY = 5000;
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800114 private static final int LOW_PRIORITY = 4000;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800115 private static final int LOWEST_PRIORITY = 0;
Hyunsun Moon4a915152016-01-14 16:56:26 -0800116
117 private static final int VXLAN_UDP_PORT = 4789;
Hyunsun Moon6d247342016-02-12 12:48:47 -0800118 private static final VlanId VLAN_WAN = VlanId.vlanId((short) 500);
119
120 private static final String PORT_NAME = "portName";
121 private static final String DATA_PLANE_INTF = "dataPlaneIntf";
122 private static final String S_TAG = "stag";
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800123
124 private final ApplicationId appId;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800125 private final FlowRuleService flowRuleService;
126 private final DeviceService deviceService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800127 private final DriverService driverService;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800128 private final GroupService groupService;
129 private final MastershipService mastershipService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800130 private final String tunnelType;
131
132 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800133 * Creates a new rule populator.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800134 *
135 * @param appId application id
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800136 * @param flowRuleService flow rule service
137 * @param deviceService device service
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800138 * @param driverService driver service
Jian Lidfba7392016-01-22 16:46:58 -0800139 * @param groupService group service
140 * @param mastershipService mastership service
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800141 * @param tunnelType tunnel type
142 */
143 public CordVtnRuleInstaller(ApplicationId appId,
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800144 FlowRuleService flowRuleService,
145 DeviceService deviceService,
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800146 DriverService driverService,
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800147 GroupService groupService,
148 MastershipService mastershipService,
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800149 String tunnelType) {
150 this.appId = appId;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800151 this.flowRuleService = flowRuleService;
152 this.deviceService = deviceService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800153 this.driverService = driverService;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800154 this.groupService = groupService;
155 this.mastershipService = mastershipService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800156 this.tunnelType = checkNotNull(tunnelType);
157 }
158
159 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800160 * Installs table miss rule to a give device.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800161 *
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800162 * @param deviceId device id to install the rules
Hyunsun Moon133fd792016-02-09 01:55:48 -0800163 * @param dpIntf data plane interface name
164 * @param dpIp data plane ip address
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800165 */
Hyunsun Moon133fd792016-02-09 01:55:48 -0800166 public void init(DeviceId deviceId, String dpIntf, IpAddress dpIp) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800167 // default is drop packets which can be accomplished without
168 // a table miss entry for all table.
Hyunsun Moon4a915152016-01-14 16:56:26 -0800169 PortNumber tunnelPort = getTunnelPort(deviceId);
Hyunsun Moon133fd792016-02-09 01:55:48 -0800170 PortNumber dpPort = getDpPort(deviceId, dpIntf);
Hyunsun Moon4a915152016-01-14 16:56:26 -0800171
Hyunsun Moon133fd792016-02-09 01:55:48 -0800172 processFirstTable(deviceId, dpPort, dpIp);
173 processInPortTable(deviceId, tunnelPort, dpPort);
174 processAccessTypeTable(deviceId, dpPort);
Hyunsun Moon6d247342016-02-12 12:48:47 -0800175 processQInQTable(deviceId, dpPort);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800176 }
177
178 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800179 * Populates basic rules that connect a VM to the other VMs in the system.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800180 *
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800181 * @param host host
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800182 * @param tunnelIp tunnel ip
183 * @param vNet openstack network
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800184 */
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800185 public void populateBasicConnectionRules(Host host, IpAddress tunnelIp, OpenstackNetwork vNet) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800186 checkNotNull(host);
187 checkNotNull(vNet);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800188
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800189 DeviceId deviceId = host.location().deviceId();
190 if (!mastershipService.isLocalMaster(deviceId)) {
191 return;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800192 }
193
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800194 PortNumber inPort = host.location().port();
195 MacAddress dstMac = host.mac();
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800196 IpAddress hostIp = host.ipAddresses().stream().findFirst().get();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800197 long tunnelId = Long.parseLong(vNet.segmentId());
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800198
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800199 OpenstackSubnet subnet = vNet.subnets().stream()
200 .findFirst()
201 .orElse(null);
202
203 if (subnet == null) {
204 log.error("Failed to get subnet for {}", host.id());
205 return;
206 }
207
208 populateLocalInPortRule(deviceId, inPort, hostIp);
209 populateDirectAccessRule(Ip4Prefix.valueOf(subnet.cidr()), Ip4Prefix.valueOf(subnet.cidr()));
Hyunsun Moon81ab23b2016-02-01 23:00:56 -0800210 populateServiceIsolationRule(Ip4Prefix.valueOf(subnet.cidr()));
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800211 populateDstIpRule(deviceId, inPort, dstMac, hostIp, tunnelId, tunnelIp);
212 populateTunnelInRule(deviceId, inPort, dstMac, tunnelId);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800213 }
214
215 /**
Hyunsun Moond5f6c3b2016-02-18 15:37:22 -0800216 * Removes all rules related to a given service VM host.
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800217 *
218 * @param host host to be removed
219 */
220 public void removeBasicConnectionRules(Host host) {
221 checkNotNull(host);
222
223 DeviceId deviceId = host.location().deviceId();
224 MacAddress mac = host.mac();
225 PortNumber port = host.location().port();
226 IpAddress ip = host.ipAddresses().stream().findFirst().orElse(null);
227
228 if (!mastershipService.isLocalMaster(deviceId)) {
229 return;
230 }
231
232 for (FlowRule flowRule : flowRuleService.getFlowRulesById(appId)) {
233 if (flowRule.deviceId().equals(deviceId)) {
234 PortNumber inPort = getInPort(flowRule);
235 if (inPort != null && inPort.equals(port)) {
236 processFlowRule(false, flowRule);
237 continue;
238 }
Hyunsun Moond5f6c3b2016-02-18 15:37:22 -0800239
240 PortNumber output = getOutputFromTreatment(flowRule);
241 if (output != null && output.equals(host.location().port())) {
242 processFlowRule(false, flowRule);
243 }
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800244 }
245
246 MacAddress dstMac = getDstMacFromTreatment(flowRule);
247 if (dstMac != null && dstMac.equals(mac)) {
248 processFlowRule(false, flowRule);
249 continue;
250 }
251
252 dstMac = getDstMacFromSelector(flowRule);
253 if (dstMac != null && dstMac.equals(mac)) {
254 processFlowRule(false, flowRule);
255 continue;
256 }
257
258 IpPrefix dstIp = getDstIpFromSelector(flowRule);
259 if (dstIp != null && dstIp.equals(ip.toIpPrefix())) {
260 processFlowRule(false, flowRule);
261 }
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800262 }
263
264 // TODO uninstall same network access rule in access table if no vm exists in the network
265 }
266
267 /**
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800268 * Populates service dependency rules.
269 *
270 * @param tService tenant cord service
271 * @param pService provider cord service
Hyunsun Moon640f183e2016-02-10 17:02:37 -0800272 * @param isBidirectional true to enable bidirectional connection between two services
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800273 */
Hyunsun Moon640f183e2016-02-10 17:02:37 -0800274 public void populateServiceDependencyRules(CordService tService, CordService pService,
275 boolean isBidirectional) {
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800276 checkNotNull(tService);
277 checkNotNull(pService);
278
279 Ip4Prefix srcRange = tService.serviceIpRange().getIp4Prefix();
280 Ip4Prefix dstRange = pService.serviceIpRange().getIp4Prefix();
281 Ip4Address serviceIp = pService.serviceIp().getIp4Address();
282
283 Map<DeviceId, GroupId> outGroups = Maps.newHashMap();
284 Map<DeviceId, Set<PortNumber>> inPorts = Maps.newHashMap();
285
286 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
287 GroupId groupId = createServiceGroup(device.id(), pService);
288 outGroups.put(device.id(), groupId);
289
290 Set<PortNumber> vms = tService.hosts().keySet()
291 .stream()
292 .filter(host -> host.location().deviceId().equals(device.id()))
293 .map(host -> host.location().port())
294 .collect(Collectors.toSet());
295 inPorts.put(device.id(), vms);
296 }
297
298 populateIndirectAccessRule(srcRange, serviceIp, outGroups);
299 populateDirectAccessRule(srcRange, dstRange);
Hyunsun Moon640f183e2016-02-10 17:02:37 -0800300 if (isBidirectional) {
301 populateDirectAccessRule(dstRange, srcRange);
302 }
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800303 populateInServiceRule(inPorts, outGroups);
304 }
305
306 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800307 * Removes service dependency rules.
308 *
309 * @param tService tenant cord service
310 * @param pService provider cord service
311 */
312 public void removeServiceDependencyRules(CordService tService, CordService pService) {
313 checkNotNull(tService);
314 checkNotNull(pService);
315
316 Ip4Prefix srcRange = tService.serviceIpRange().getIp4Prefix();
317 Ip4Prefix dstRange = pService.serviceIpRange().getIp4Prefix();
318 IpPrefix serviceIp = pService.serviceIp().toIpPrefix();
319
320 Map<DeviceId, GroupId> outGroups = Maps.newHashMap();
321 GroupKey groupKey = new DefaultGroupKey(pService.id().id().getBytes());
322
323 deviceService.getAvailableDevices(SWITCH).forEach(device -> {
324 Group group = groupService.getGroup(device.id(), groupKey);
325 if (group != null) {
326 outGroups.put(device.id(), group.id());
327 }
328 });
329
330 for (FlowRule flowRule : flowRuleService.getFlowRulesById(appId)) {
331 IpPrefix dstIp = getDstIpFromSelector(flowRule);
332 IpPrefix srcIp = getSrcIpFromSelector(flowRule);
333
334 if (dstIp != null && dstIp.equals(serviceIp)) {
335 processFlowRule(false, flowRule);
336 continue;
337 }
338
339 if (dstIp != null && srcIp != null) {
340 if (dstIp.equals(dstRange) && srcIp.equals(srcRange)) {
341 processFlowRule(false, flowRule);
342 continue;
343 }
344
345 if (dstIp.equals(srcRange) && srcIp.equals(dstRange)) {
346 processFlowRule(false, flowRule);
347 continue;
348 }
349 }
350
351 GroupId groupId = getGroupIdFromTreatment(flowRule);
352 if (groupId != null && groupId.equals(outGroups.get(flowRule.deviceId()))) {
353 processFlowRule(false, flowRule);
354 }
355 }
356
357 // TODO remove the group if it is not in use
358 }
359
360 /**
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800361 * Updates group buckets for a given service to all devices.
362 *
363 * @param service cord service
364 */
365 public void updateServiceGroup(CordService service) {
366 checkNotNull(service);
367
368 GroupKey groupKey = getGroupKey(service.id());
369
370 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
371 DeviceId deviceId = device.id();
372 if (!mastershipService.isLocalMaster(deviceId)) {
373 continue;
374 }
375
376 Group group = groupService.getGroup(deviceId, groupKey);
377 if (group == null) {
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800378 log.trace("No group exists for service {} in {}, do nothing.", service.id(), deviceId);
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800379 continue;
380 }
381
382 List<GroupBucket> oldBuckets = group.buckets().buckets();
383 List<GroupBucket> newBuckets = getServiceGroupBuckets(
384 deviceId, service.segmentationId(), service.hosts()).buckets();
385
386 if (oldBuckets.equals(newBuckets)) {
387 continue;
388 }
389
390 List<GroupBucket> bucketsToRemove = new ArrayList<>(oldBuckets);
391 bucketsToRemove.removeAll(newBuckets);
392 if (!bucketsToRemove.isEmpty()) {
393 groupService.removeBucketsFromGroup(
394 deviceId,
395 groupKey,
396 new GroupBuckets(bucketsToRemove),
397 groupKey, appId);
398 }
399
400 List<GroupBucket> bucketsToAdd = new ArrayList<>(newBuckets);
401 bucketsToAdd.removeAll(oldBuckets);
402 if (!bucketsToAdd.isEmpty()) {
403 groupService.addBucketsToGroup(
404 deviceId,
405 groupKey,
406 new GroupBuckets(bucketsToAdd),
407 groupKey, appId);
408 }
409 }
410 }
411
412 /**
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800413 * Populates flow rules for management network access.
414 *
415 * @param host host which has management network interface
416 * @param mService management network service
417 */
418 public void populateManagementNetworkRules(Host host, CordService mService) {
419 checkNotNull(mService);
420
421 DeviceId deviceId = host.location().deviceId();
422 IpAddress hostIp = host.ipAddresses().stream().findFirst().get();
423
Hyunsun Moon6d247342016-02-12 12:48:47 -0800424 if (!mastershipService.isLocalMaster(deviceId)) {
425 return;
426 }
427
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800428 TrafficSelector selector = DefaultTrafficSelector.builder()
429 .matchEthType(Ethernet.TYPE_ARP)
430 .matchArpTpa(mService.serviceIp().getIp4Address())
431 .build();
432
433 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
434 .setOutput(PortNumber.LOCAL)
435 .build();
436
437 FlowRule flowRule = DefaultFlowRule.builder()
438 .fromApp(appId)
439 .withSelector(selector)
440 .withTreatment(treatment)
441 .withPriority(MANAGEMENT_PRIORITY)
442 .forDevice(deviceId)
443 .forTable(TABLE_FIRST)
444 .makePermanent()
445 .build();
446
447 processFlowRule(true, flowRule);
448
449 selector = DefaultTrafficSelector.builder()
450 .matchInPort(PortNumber.LOCAL)
451 .matchEthType(Ethernet.TYPE_ARP)
452 .matchArpTpa(hostIp.getIp4Address())
453 .build();
454
455 treatment = DefaultTrafficTreatment.builder()
456 .setOutput(host.location().port())
457 .build();
458
459 flowRule = DefaultFlowRule.builder()
460 .fromApp(appId)
461 .withSelector(selector)
462 .withTreatment(treatment)
463 .withPriority(MANAGEMENT_PRIORITY)
464 .forDevice(deviceId)
465 .forTable(TABLE_FIRST)
466 .makePermanent()
467 .build();
468
469 processFlowRule(true, flowRule);
470
471 selector = DefaultTrafficSelector.builder()
472 .matchInPort(PortNumber.LOCAL)
473 .matchEthType(Ethernet.TYPE_IPV4)
474 .matchIPDst(mService.serviceIpRange())
475 .build();
476
477 treatment = DefaultTrafficTreatment.builder()
478 .transition(TABLE_DST_IP)
479 .build();
480
481 flowRule = DefaultFlowRule.builder()
482 .fromApp(appId)
483 .withSelector(selector)
484 .withTreatment(treatment)
485 .withPriority(MANAGEMENT_PRIORITY)
486 .forDevice(deviceId)
487 .forTable(TABLE_FIRST)
488 .makePermanent()
489 .build();
490
491 processFlowRule(true, flowRule);
492
493 selector = DefaultTrafficSelector.builder()
494 .matchEthType(Ethernet.TYPE_IPV4)
495 .matchIPDst(mService.serviceIp().toIpPrefix())
496 .build();
497
498 treatment = DefaultTrafficTreatment.builder()
499 .setOutput(PortNumber.LOCAL)
500 .build();
501
502 flowRule = DefaultFlowRule.builder()
503 .fromApp(appId)
504 .withSelector(selector)
505 .withTreatment(treatment)
506 .withPriority(MANAGEMENT_PRIORITY)
507 .forDevice(deviceId)
508 .forTable(TABLE_ACCESS_TYPE)
509 .makePermanent()
510 .build();
511
512 processFlowRule(true, flowRule);
513 }
514
515 /**
516 * Removes management network access rules.
517 *
518 * @param host host to be removed
519 * @param mService service for management network
520 */
521 public void removeManagementNetworkRules(Host host, CordService mService) {
522 checkNotNull(mService);
523
Hyunsun Moon6d247342016-02-12 12:48:47 -0800524 if (!mastershipService.isLocalMaster(host.location().deviceId())) {
525 return;
526 }
Hyunsun Moond5f6c3b2016-02-18 15:37:22 -0800527 // TODO remove management network specific rules
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800528 }
529
530 /**
Hyunsun Moon6d247342016-02-12 12:48:47 -0800531 * Populates rules for vSG VM.
532 *
533 * @param vSgHost vSG host
534 * @param vSgIps set of ip addresses of vSGs running inside the vSG VM
535 */
536 public void populateSubscriberGatewayRules(Host vSgHost, Set<IpAddress> vSgIps) {
537 VlanId serviceVlan = getServiceVlan(vSgHost);
538 PortNumber dpPort = getDpPort(vSgHost);
539
540 if (serviceVlan == null || dpPort == null) {
541 log.warn("Failed to populate rules for vSG VM {}", vSgHost.id());
542 return;
543 }
544
545 // for traffics with s-tag, strip the tag and take through the vSG VM
546 TrafficSelector selector = DefaultTrafficSelector.builder()
Hyunsun Moond5f6c3b2016-02-18 15:37:22 -0800547 .matchInPort(dpPort)
Hyunsun Moon6d247342016-02-12 12:48:47 -0800548 .matchVlanId(serviceVlan)
549 .build();
550
551 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Hyunsun Moon6d247342016-02-12 12:48:47 -0800552 .setOutput(vSgHost.location().port())
553 .build();
554
555 FlowRule flowRule = DefaultFlowRule.builder()
556 .fromApp(appId)
557 .withSelector(selector)
558 .withTreatment(treatment)
559 .withPriority(DEFAULT_PRIORITY)
560 .forDevice(vSgHost.location().deviceId())
561 .forTable(TABLE_Q_IN_Q)
562 .makePermanent()
563 .build();
564
565 processFlowRule(true, flowRule);
566
567 // for traffics with customer vlan, tag with the service vlan based on input port with
568 // lower priority to avoid conflict with WAN tag
569 selector = DefaultTrafficSelector.builder()
570 .matchInPort(vSgHost.location().port())
Hyunsun Moond5f6c3b2016-02-18 15:37:22 -0800571 .matchVlanId(serviceVlan)
Hyunsun Moon6d247342016-02-12 12:48:47 -0800572 .build();
573
574 treatment = DefaultTrafficTreatment.builder()
Hyunsun Moon6d247342016-02-12 12:48:47 -0800575 .setOutput(dpPort)
576 .build();
577
578 flowRule = DefaultFlowRule.builder()
579 .fromApp(appId)
580 .withSelector(selector)
581 .withTreatment(treatment)
Hyunsun Moond5f6c3b2016-02-18 15:37:22 -0800582 .withPriority(DEFAULT_PRIORITY)
Hyunsun Moon6d247342016-02-12 12:48:47 -0800583 .forDevice(vSgHost.location().deviceId())
584 .forTable(TABLE_Q_IN_Q)
585 .makePermanent()
586 .build();
587
588 processFlowRule(true, flowRule);
589
590 // for traffic coming from WAN, tag 500 and take through the vSG VM
591 // based on destination ip
592 vSgIps.stream().forEach(ip -> {
593 TrafficSelector downstream = DefaultTrafficSelector.builder()
594 .matchEthType(Ethernet.TYPE_IPV4)
595 .matchIPDst(ip.toIpPrefix())
596 .build();
597
598 TrafficTreatment downstreamTreatment = DefaultTrafficTreatment.builder()
599 .pushVlan()
600 .setVlanId(VLAN_WAN)
601 .setEthDst(vSgHost.mac())
602 .setOutput(vSgHost.location().port())
603 .build();
604
605 FlowRule downstreamFlowRule = DefaultFlowRule.builder()
606 .fromApp(appId)
607 .withSelector(downstream)
608 .withTreatment(downstreamTreatment)
609 .withPriority(DEFAULT_PRIORITY)
610 .forDevice(vSgHost.location().deviceId())
611 .forTable(TABLE_DST_IP)
612 .makePermanent()
613 .build();
614
615 processFlowRule(true, downstreamFlowRule);
616 });
617
618 // remove downstream flow rules for the vSG not shown in vSgIps
619 for (FlowRule rule : flowRuleService.getFlowRulesById(appId)) {
620 if (!rule.deviceId().equals(vSgHost.location().deviceId())) {
621 continue;
622 }
623 PortNumber output = getOutputFromTreatment(rule);
624 if (output == null || !output.equals(vSgHost.location().port()) ||
625 !isVlanPushFromTreatment(rule)) {
626 continue;
627 }
628
629 IpPrefix dstIp = getDstIpFromSelector(rule);
630 if (dstIp != null && !vSgIps.contains(dstIp.address())) {
631 processFlowRule(false, rule);
632 }
633 }
634 }
635
636 /**
Hyunsun Moon4a915152016-01-14 16:56:26 -0800637 * Populates default rules on the first table.
Hyunsun Moon133fd792016-02-09 01:55:48 -0800638 * It includes the rules for shuttling vxlan-encapped packets between ovs and
639 * linux stack,and external network connectivity.
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
643 * @param dpIp data plane ip address
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800644 */
Hyunsun Moon133fd792016-02-09 01:55:48 -0800645 private void processFirstTable(DeviceId deviceId, PortNumber dpPort, IpAddress dpIp) {
Hyunsun Moon4a915152016-01-14 16:56:26 -0800646 // take vxlan packet out onto the physical port
647 TrafficSelector selector = DefaultTrafficSelector.builder()
648 .matchInPort(PortNumber.LOCAL)
649 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800650
Hyunsun Moon4a915152016-01-14 16:56:26 -0800651 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Hyunsun Moon133fd792016-02-09 01:55:48 -0800652 .setOutput(dpPort)
Hyunsun Moon4a915152016-01-14 16:56:26 -0800653 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800654
Hyunsun Moon4a915152016-01-14 16:56:26 -0800655 FlowRule flowRule = DefaultFlowRule.builder()
656 .fromApp(appId)
657 .withSelector(selector)
658 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800659 .withPriority(HIGH_PRIORITY)
Hyunsun Moon4a915152016-01-14 16:56:26 -0800660 .forDevice(deviceId)
661 .forTable(TABLE_FIRST)
662 .makePermanent()
663 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800664
Hyunsun Moon4a915152016-01-14 16:56:26 -0800665 processFlowRule(true, flowRule);
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800666
Hyunsun Moon4a915152016-01-14 16:56:26 -0800667 // take a vxlan encap'd packet through the Linux stack
668 selector = DefaultTrafficSelector.builder()
Hyunsun Moon133fd792016-02-09 01:55:48 -0800669 .matchInPort(dpPort)
Hyunsun Moon4a915152016-01-14 16:56:26 -0800670 .matchEthType(Ethernet.TYPE_IPV4)
671 .matchIPProtocol(IPv4.PROTOCOL_UDP)
672 .matchUdpDst(TpPort.tpPort(VXLAN_UDP_PORT))
673 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800674
Hyunsun Moon4a915152016-01-14 16:56:26 -0800675 treatment = DefaultTrafficTreatment.builder()
676 .setOutput(PortNumber.LOCAL)
677 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800678
Hyunsun Moon4a915152016-01-14 16:56:26 -0800679 flowRule = DefaultFlowRule.builder()
680 .fromApp(appId)
681 .withSelector(selector)
682 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800683 .withPriority(HIGH_PRIORITY)
Hyunsun Moon4a915152016-01-14 16:56:26 -0800684 .forDevice(deviceId)
685 .forTable(TABLE_FIRST)
686 .makePermanent()
687 .build();
688
689 processFlowRule(true, flowRule);
690
Hyunsun Moon133fd792016-02-09 01:55:48 -0800691 // take a packet to the data plane ip through Linux stack
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800692 selector = DefaultTrafficSelector.builder()
Hyunsun Moon133fd792016-02-09 01:55:48 -0800693 .matchInPort(dpPort)
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800694 .matchEthType(Ethernet.TYPE_IPV4)
Hyunsun Moon133fd792016-02-09 01:55:48 -0800695 .matchIPDst(dpIp.toIpPrefix())
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800696 .build();
697
698 treatment = DefaultTrafficTreatment.builder()
699 .setOutput(PortNumber.LOCAL)
700 .build();
701
702 flowRule = DefaultFlowRule.builder()
703 .fromApp(appId)
704 .withSelector(selector)
705 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800706 .withPriority(HIGH_PRIORITY)
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800707 .forDevice(deviceId)
708 .forTable(TABLE_FIRST)
709 .makePermanent()
710 .build();
711
712 processFlowRule(true, flowRule);
713
714 // take an arp packet from physical through Linux stack
715 selector = DefaultTrafficSelector.builder()
Hyunsun Moon133fd792016-02-09 01:55:48 -0800716 .matchInPort(dpPort)
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800717 .matchEthType(Ethernet.TYPE_ARP)
Hyunsun Moon6d247342016-02-12 12:48:47 -0800718 .matchArpTpa(dpIp.getIp4Address())
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800719 .build();
720
721 treatment = DefaultTrafficTreatment.builder()
722 .setOutput(PortNumber.LOCAL)
723 .build();
724
725 flowRule = DefaultFlowRule.builder()
726 .fromApp(appId)
727 .withSelector(selector)
728 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800729 .withPriority(HIGH_PRIORITY)
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800730 .forDevice(deviceId)
731 .forTable(TABLE_FIRST)
732 .makePermanent()
733 .build();
734
735 processFlowRule(true, flowRule);
736
Hyunsun Moon4a915152016-01-14 16:56:26 -0800737 // take all else to the next table
738 selector = DefaultTrafficSelector.builder()
739 .build();
740
741 treatment = DefaultTrafficTreatment.builder()
742 .transition(TABLE_IN_PORT)
743 .build();
744
745 flowRule = DefaultFlowRule.builder()
746 .fromApp(appId)
747 .withSelector(selector)
748 .withTreatment(treatment)
749 .withPriority(LOWEST_PRIORITY)
750 .forDevice(deviceId)
751 .forTable(TABLE_FIRST)
752 .makePermanent()
753 .build();
754
755 processFlowRule(true, flowRule);
Hyunsun Moon6d247342016-02-12 12:48:47 -0800756
757 // take all vlan tagged packet to the Q_IN_Q table
758 selector = DefaultTrafficSelector.builder()
759 .matchVlanId(VlanId.ANY)
760 .build();
761
762 treatment = DefaultTrafficTreatment.builder()
763 .transition(TABLE_Q_IN_Q)
764 .build();
765
766 flowRule = DefaultFlowRule.builder()
767 .fromApp(appId)
768 .withSelector(selector)
769 .withTreatment(treatment)
770 .withPriority(VSG_PRIORITY)
771 .forDevice(deviceId)
772 .forTable(TABLE_FIRST)
773 .makePermanent()
774 .build();
775
776 processFlowRule(true, flowRule);
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800777 }
778
779 /**
Hyunsun Moon133fd792016-02-09 01:55:48 -0800780 * Forward table miss packets in ACCESS_TYPE table to data plane port.
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800781 *
782 * @param deviceId device id
Hyunsun Moon133fd792016-02-09 01:55:48 -0800783 * @param dpPort data plane interface port number
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800784 */
Hyunsun Moon133fd792016-02-09 01:55:48 -0800785 private void processAccessTypeTable(DeviceId deviceId, PortNumber dpPort) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800786 TrafficSelector selector = DefaultTrafficSelector.builder()
787 .build();
788
789 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Hyunsun Moon133fd792016-02-09 01:55:48 -0800790 .setOutput(dpPort)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800791 .build();
792
793 FlowRule flowRule = DefaultFlowRule.builder()
794 .fromApp(appId)
795 .withSelector(selector)
796 .withTreatment(treatment)
797 .withPriority(LOWEST_PRIORITY)
798 .forDevice(deviceId)
799 .forTable(TABLE_ACCESS_TYPE)
800 .makePermanent()
801 .build();
802
803 processFlowRule(true, flowRule);
804 }
805
806 /**
Hyunsun Moon4a915152016-01-14 16:56:26 -0800807 * Populates default rules for IN_PORT table.
808 * All packets from tunnel port are forwarded to TUNNEL_ID table and all packets
Hyunsun Moon133fd792016-02-09 01:55:48 -0800809 * from data plane interface port to ACCESS_TYPE table.
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800810 *
811 * @param deviceId device id to install the rules
Hyunsun Moon4a915152016-01-14 16:56:26 -0800812 * @param tunnelPort tunnel port number
Hyunsun Moon133fd792016-02-09 01:55:48 -0800813 * @param dpPort data plane interface port number
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800814 */
Hyunsun Moon133fd792016-02-09 01:55:48 -0800815 private void processInPortTable(DeviceId deviceId, PortNumber tunnelPort, PortNumber dpPort) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800816 checkNotNull(tunnelPort);
817
818 TrafficSelector selector = DefaultTrafficSelector.builder()
819 .matchInPort(tunnelPort)
820 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800821
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800822 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
823 .transition(TABLE_TUNNEL_IN)
824 .build();
825
826 FlowRule flowRule = DefaultFlowRule.builder()
827 .fromApp(appId)
828 .withSelector(selector)
829 .withTreatment(treatment)
830 .withPriority(DEFAULT_PRIORITY)
831 .forDevice(deviceId)
832 .forTable(TABLE_IN_PORT)
833 .makePermanent()
834 .build();
835
836 processFlowRule(true, flowRule);
Hyunsun Moon4a915152016-01-14 16:56:26 -0800837
838 selector = DefaultTrafficSelector.builder()
Hyunsun Moon133fd792016-02-09 01:55:48 -0800839 .matchInPort(dpPort)
Hyunsun Moon4a915152016-01-14 16:56:26 -0800840 .build();
841
842 treatment = DefaultTrafficTreatment.builder()
843 .transition(TABLE_DST_IP)
844 .build();
845
846 flowRule = DefaultFlowRule.builder()
847 .fromApp(appId)
848 .withSelector(selector)
849 .withTreatment(treatment)
850 .withPriority(DEFAULT_PRIORITY)
851 .forDevice(deviceId)
852 .forTable(TABLE_IN_PORT)
853 .makePermanent()
854 .build();
855
856 processFlowRule(true, flowRule);
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800857 }
858
859 /**
Hyunsun Moon6d247342016-02-12 12:48:47 -0800860 * Populates default rules for Q_IN_Q table.
861 *
862 * @param deviceId device id
863 * @param dpPort data plane interface port number
864 */
865 private void processQInQTable(DeviceId deviceId, PortNumber dpPort) {
866 // for traffic going out to WAN, strip vid 500 and take through data plane interface
867 TrafficSelector selector = DefaultTrafficSelector.builder()
868 .matchVlanId(VLAN_WAN)
869 .build();
870
871 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
872 .popVlan()
873 .setOutput(dpPort)
874 .build();
875
876 FlowRule flowRule = DefaultFlowRule.builder()
877 .fromApp(appId)
878 .withSelector(selector)
879 .withTreatment(treatment)
880 .withPriority(DEFAULT_PRIORITY)
881 .forDevice(deviceId)
882 .forTable(TABLE_Q_IN_Q)
883 .makePermanent()
884 .build();
885
886 processFlowRule(true, flowRule);
887
888 selector = DefaultTrafficSelector.builder()
889 .matchVlanId(VLAN_WAN)
890 .matchEthType(Ethernet.TYPE_ARP)
891 .build();
892
893 treatment = DefaultTrafficTreatment.builder()
894 .setOutput(PortNumber.CONTROLLER)
895 .build();
896
897 flowRule = DefaultFlowRule.builder()
898 .fromApp(appId)
899 .withSelector(selector)
900 .withTreatment(treatment)
901 .withPriority(HIGH_PRIORITY)
902 .forDevice(deviceId)
903 .forTable(TABLE_Q_IN_Q)
904 .makePermanent()
905 .build();
906
907 processFlowRule(true, flowRule);
908 }
909
910 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800911 * Populates rules for local in port in IN_PORT table.
912 * Flows from a given in port, whose source IP is service IP transition
913 * to DST_TYPE table. Other flows transition to IN_SERVICE table.
914 *
915 * @param deviceId device id to install the rules
916 * @param inPort in port
917 * @param srcIp source ip
918 */
919 private void populateLocalInPortRule(DeviceId deviceId, PortNumber inPort, IpAddress srcIp) {
920 TrafficSelector selector = DefaultTrafficSelector.builder()
921 .matchInPort(inPort)
922 .matchEthType(Ethernet.TYPE_IPV4)
923 .matchIPSrc(srcIp.toIpPrefix())
924 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800925
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800926 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
927 .transition(TABLE_ACCESS_TYPE)
928 .build();
929
930
931 FlowRule flowRule = DefaultFlowRule.builder()
932 .fromApp(appId)
933 .withSelector(selector)
934 .withTreatment(treatment)
935 .withPriority(DEFAULT_PRIORITY)
936 .forDevice(deviceId)
937 .forTable(TABLE_IN_PORT)
938 .makePermanent()
939 .build();
940
941 processFlowRule(true, flowRule);
942
943 selector = DefaultTrafficSelector.builder()
944 .matchInPort(inPort)
945 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800946
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800947 treatment = DefaultTrafficTreatment.builder()
948 .transition(TABLE_IN_SERVICE)
949 .build();
950
951 flowRule = DefaultFlowRule.builder()
952 .fromApp(appId)
953 .withSelector(selector)
954 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800955 .withPriority(LOW_PRIORITY)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800956 .forDevice(deviceId)
957 .forTable(TABLE_IN_PORT)
958 .makePermanent()
959 .build();
960
961 processFlowRule(true, flowRule);
962 }
963
964 /**
965 * Populates direct VM access rules for ACCESS_TYPE table.
966 * These rules are installed to all devices.
967 *
968 * @param srcRange source ip range
969 * @param dstRange destination ip range
970 */
971 private void populateDirectAccessRule(Ip4Prefix srcRange, Ip4Prefix dstRange) {
972 TrafficSelector selector = DefaultTrafficSelector.builder()
973 .matchEthType(Ethernet.TYPE_IPV4)
974 .matchIPSrc(srcRange)
975 .matchIPDst(dstRange)
976 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800977
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800978 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
979 .transition(TABLE_DST_IP)
980 .build();
981
982 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
983 FlowRule flowRuleDirect = DefaultFlowRule.builder()
984 .fromApp(appId)
985 .withSelector(selector)
986 .withTreatment(treatment)
Hyunsun Moon81ab23b2016-02-01 23:00:56 -0800987 .withPriority(DEFAULT_PRIORITY)
988 .forDevice(device.id())
989 .forTable(TABLE_ACCESS_TYPE)
990 .makePermanent()
991 .build();
992
993 processFlowRule(true, flowRuleDirect);
994 }
995 }
996
997 /**
998 * Populates drop rules that does not match any direct access rules but has
999 * destination to a different service network in ACCESS_TYPE table.
1000 *
1001 * @param dstRange destination ip range
1002 */
1003 private void populateServiceIsolationRule(Ip4Prefix dstRange) {
1004 TrafficSelector selector = DefaultTrafficSelector.builder()
1005 .matchEthType(Ethernet.TYPE_IPV4)
1006 .matchIPDst(dstRange)
1007 .build();
1008
1009 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
1010 .drop()
1011 .build();
1012
1013 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
1014 FlowRule flowRuleDirect = DefaultFlowRule.builder()
1015 .fromApp(appId)
1016 .withSelector(selector)
1017 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -08001018 .withPriority(LOW_PRIORITY)
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001019 .forDevice(device.id())
1020 .forTable(TABLE_ACCESS_TYPE)
1021 .makePermanent()
1022 .build();
1023
1024 processFlowRule(true, flowRuleDirect);
1025 }
1026 }
1027
1028 /**
1029 * Populates indirect service access rules for ACCESS_TYPE table.
1030 * These rules are installed to all devices.
1031 *
1032 * @param srcRange source range
1033 * @param serviceIp service ip
1034 * @param outGroups list of output group
1035 */
1036 private void populateIndirectAccessRule(Ip4Prefix srcRange, Ip4Address serviceIp,
1037 Map<DeviceId, GroupId> outGroups) {
1038 TrafficSelector selector = DefaultTrafficSelector.builder()
1039 .matchEthType(Ethernet.TYPE_IPV4)
1040 .matchIPSrc(srcRange)
1041 .matchIPDst(serviceIp.toIpPrefix())
1042 .build();
1043
1044 for (Map.Entry<DeviceId, GroupId> outGroup : outGroups.entrySet()) {
1045 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
1046 .group(outGroup.getValue())
1047 .build();
1048
1049 FlowRule flowRule = DefaultFlowRule.builder()
1050 .fromApp(appId)
1051 .withSelector(selector)
1052 .withTreatment(treatment)
Hyunsun Moon81ab23b2016-02-01 23:00:56 -08001053 .withPriority(HIGH_PRIORITY)
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001054 .forDevice(outGroup.getKey())
1055 .forTable(TABLE_ACCESS_TYPE)
1056 .makePermanent()
1057 .build();
1058
1059 processFlowRule(true, flowRule);
1060 }
1061 }
1062
1063 /**
1064 * Populates flow rules for IN_SERVICE table.
1065 *
1066 * @param inPorts list of inports related to the service for each device
1067 * @param outGroups set of output groups
1068 */
1069 private void populateInServiceRule(Map<DeviceId, Set<PortNumber>> inPorts, Map<DeviceId, GroupId> outGroups) {
1070 checkNotNull(inPorts);
1071 checkNotNull(outGroups);
1072
1073 for (Map.Entry<DeviceId, Set<PortNumber>> entry : inPorts.entrySet()) {
1074 Set<PortNumber> ports = entry.getValue();
1075 DeviceId deviceId = entry.getKey();
1076
1077 GroupId groupId = outGroups.get(deviceId);
1078 if (groupId == null) {
1079 continue;
1080 }
1081
1082 ports.stream().forEach(port -> {
1083 TrafficSelector selector = DefaultTrafficSelector.builder()
1084 .matchInPort(port)
1085 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -08001086
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001087 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
1088 .group(groupId)
1089 .build();
1090
1091 FlowRule flowRule = DefaultFlowRule.builder()
1092 .fromApp(appId)
1093 .withSelector(selector)
1094 .withTreatment(treatment)
1095 .withPriority(DEFAULT_PRIORITY)
1096 .forDevice(deviceId)
1097 .forTable(TABLE_IN_SERVICE)
1098 .makePermanent()
1099 .build();
1100
1101 processFlowRule(true, flowRule);
1102 });
1103 }
1104 }
1105
1106 /**
1107 * Populates flow rules for DST_IP table.
1108 *
1109 * @param deviceId device id
1110 * @param inPort in port
1111 * @param dstMac mac address
1112 * @param dstIp destination ip
1113 * @param tunnelId tunnel id
1114 * @param tunnelIp tunnel remote ip
1115 */
1116 private void populateDstIpRule(DeviceId deviceId, PortNumber inPort, MacAddress dstMac,
1117 IpAddress dstIp, long tunnelId, IpAddress tunnelIp) {
1118 TrafficSelector selector = DefaultTrafficSelector.builder()
1119 .matchEthType(Ethernet.TYPE_IPV4)
1120 .matchIPDst(dstIp.toIpPrefix())
1121 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -08001122
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001123 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
1124 .setEthDst(dstMac)
1125 .setOutput(inPort)
1126 .build();
1127
1128 FlowRule flowRule = DefaultFlowRule.builder()
1129 .fromApp(appId)
1130 .withSelector(selector)
1131 .withTreatment(treatment)
1132 .withPriority(DEFAULT_PRIORITY)
1133 .forDevice(deviceId)
1134 .forTable(TABLE_DST_IP)
1135 .makePermanent()
1136 .build();
1137
1138 processFlowRule(true, flowRule);
1139
1140 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
1141 if (device.id().equals(deviceId)) {
1142 continue;
1143 }
1144
1145 ExtensionTreatment tunnelDst = getTunnelDst(device.id(), tunnelIp.getIp4Address());
1146 if (tunnelDst == null) {
1147 continue;
1148 }
1149
1150 treatment = DefaultTrafficTreatment.builder()
1151 .setEthDst(dstMac)
1152 .setTunnelId(tunnelId)
1153 .extension(tunnelDst, device.id())
1154 .setOutput(getTunnelPort(device.id()))
1155 .build();
1156
1157 flowRule = DefaultFlowRule.builder()
1158 .fromApp(appId)
1159 .withSelector(selector)
1160 .withTreatment(treatment)
1161 .withPriority(DEFAULT_PRIORITY)
1162 .forDevice(device.id())
1163 .forTable(TABLE_DST_IP)
1164 .makePermanent()
1165 .build();
1166
1167 processFlowRule(true, flowRule);
1168 }
1169 }
1170
1171 /**
1172 * Populates flow rules for TUNNEL_ID table.
1173 *
1174 * @param deviceId device id
1175 * @param inPort in port
1176 * @param mac mac address
1177 * @param tunnelId tunnel id
1178 */
1179 private void populateTunnelInRule(DeviceId deviceId, PortNumber inPort, MacAddress mac, long tunnelId) {
1180 TrafficSelector selector = DefaultTrafficSelector.builder()
1181 .matchTunnelId(tunnelId)
1182 .matchEthDst(mac)
1183 .build();
1184
1185 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
1186 .setOutput(inPort)
1187 .build();
1188
1189 FlowRule flowRule = DefaultFlowRule.builder()
1190 .fromApp(appId)
1191 .withSelector(selector)
1192 .withTreatment(treatment)
1193 .withPriority(DEFAULT_PRIORITY)
1194 .forDevice(deviceId)
1195 .forTable(TABLE_TUNNEL_IN)
1196 .makePermanent()
1197 .build();
1198
1199 processFlowRule(true, flowRule);
1200 }
1201
1202 /**
1203 * Installs or uninstall a given rule.
1204 *
1205 * @param install true to install, false to uninstall
1206 * @param rule rule
1207 */
1208 private void processFlowRule(boolean install, FlowRule rule) {
1209 FlowRuleOperations.Builder oBuilder = FlowRuleOperations.builder();
1210 oBuilder = install ? oBuilder.add(rule) : oBuilder.remove(rule);
1211
1212 flowRuleService.apply(oBuilder.build(new FlowRuleOperationsContext() {
1213 @Override
1214 public void onError(FlowRuleOperations ops) {
1215 log.error(String.format("Failed %s, %s", ops.toString(), rule.toString()));
1216 }
1217 }));
1218 }
1219
1220 /**
1221 * Returns tunnel port of the device.
1222 *
1223 * @param deviceId device id
1224 * @return tunnel port number, or null if no tunnel port exists on a given device
1225 */
1226 private PortNumber getTunnelPort(DeviceId deviceId) {
Hyunsun Moon5a4346f2016-01-15 11:41:14 -08001227 Port port = deviceService.getPorts(deviceId).stream()
Hyunsun Moon6d247342016-02-12 12:48:47 -08001228 .filter(p -> p.annotations().value(PORT_NAME).contains(tunnelType))
1229 .findFirst().orElse(null);
Hyunsun Moon5a4346f2016-01-15 11:41:14 -08001230
1231 return port == null ? null : port.number();
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001232 }
1233
1234 /**
Hyunsun Moon133fd792016-02-09 01:55:48 -08001235 * Returns data plane interface port name of a given device.
Hyunsun Moon4a915152016-01-14 16:56:26 -08001236 *
1237 * @param deviceId device id
Hyunsun Moon133fd792016-02-09 01:55:48 -08001238 * @param dpIntf data plane interface port name
1239 * @return data plane interface port number, or null if no such port exists
Hyunsun Moon4a915152016-01-14 16:56:26 -08001240 */
Hyunsun Moon133fd792016-02-09 01:55:48 -08001241 private PortNumber getDpPort(DeviceId deviceId, String dpIntf) {
Hyunsun Moon5a4346f2016-01-15 11:41:14 -08001242 Port port = deviceService.getPorts(deviceId).stream()
Hyunsun Moon6d247342016-02-12 12:48:47 -08001243 .filter(p -> p.annotations().value(PORT_NAME).contains(dpIntf) &&
1244 p.isEnabled())
1245 .findFirst().orElse(null);
Hyunsun Moon5a4346f2016-01-15 11:41:14 -08001246
1247 return port == null ? null : port.number();
Hyunsun Moon4a915152016-01-14 16:56:26 -08001248 }
1249
Hyunsun Moon6d247342016-02-12 12:48:47 -08001250 /** Returns data plane interface port number of a given host.
1251 *
1252 * @param host host
1253 * @return port number, or null
1254 */
1255 private PortNumber getDpPort(Host host) {
1256 String portName = host.annotations().value(DATA_PLANE_INTF);
1257 return portName == null ? null : getDpPort(host.location().deviceId(), portName);
1258 }
1259
1260 /**
1261 * Returns service vlan from a given host.
1262 *
1263 * @param host host
1264 * @return vlan id, or null
1265 */
1266 private VlanId getServiceVlan(Host host) {
1267 String serviceVlan = host.annotations().value(S_TAG);
1268 return serviceVlan == null ? null : VlanId.vlanId(Short.parseShort(serviceVlan));
1269 }
1270
Hyunsun Moon4a915152016-01-14 16:56:26 -08001271 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001272 * Returns the inport from a given flow rule if the rule contains the match of it.
1273 *
1274 * @param flowRule flow rule
1275 * @return port number, or null if the rule doesn't have inport match
1276 */
1277 private PortNumber getInPort(FlowRule flowRule) {
1278 Criterion criterion = flowRule.selector().getCriterion(IN_PORT);
1279 if (criterion != null && criterion instanceof PortCriterion) {
1280 PortCriterion port = (PortCriterion) criterion;
1281 return port.port();
1282 } else {
1283 return null;
1284 }
1285 }
1286
1287 /**
1288 * Returns the destination mac address from a given flow rule if the rule
1289 * contains the instruction of it.
1290 *
1291 * @param flowRule flow rule
1292 * @return mac address, or null if the rule doesn't have destination mac instruction
1293 */
1294 private MacAddress getDstMacFromTreatment(FlowRule flowRule) {
1295 Instruction instruction = flowRule.treatment().allInstructions().stream()
1296 .filter(inst -> inst instanceof ModEtherInstruction &&
1297 ((ModEtherInstruction) inst).subtype().equals(ETH_DST))
1298 .findFirst()
1299 .orElse(null);
1300
1301 if (instruction == null) {
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001302 return null;
1303 }
1304
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001305 return ((ModEtherInstruction) instruction).mac();
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001306 }
1307
1308 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001309 * Returns the destination mac address from a given flow rule if the rule
1310 * contains the match of it.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001311 *
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001312 * @param flowRule flow rule
1313 * @return mac address, or null if the rule doesn't have destination mac match
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001314 */
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001315 private MacAddress getDstMacFromSelector(FlowRule flowRule) {
1316 Criterion criterion = flowRule.selector().getCriterion(Criterion.Type.ETH_DST);
1317 if (criterion != null && criterion instanceof EthCriterion) {
1318 EthCriterion eth = (EthCriterion) criterion;
1319 return eth.mac();
1320 } else {
1321 return null;
1322 }
1323 }
1324
1325 /**
1326 * Returns the destination IP from a given flow rule if the rule contains
1327 * the match of it.
1328 *
1329 * @param flowRule flow rule
1330 * @return ip prefix, or null if the rule doesn't have ip match
1331 */
1332 private IpPrefix getDstIpFromSelector(FlowRule flowRule) {
1333 Criterion criterion = flowRule.selector().getCriterion(IPV4_DST);
1334 if (criterion != null && criterion instanceof IPCriterion) {
1335 IPCriterion ip = (IPCriterion) criterion;
1336 return ip.ip();
1337 } else {
1338 return null;
1339 }
1340 }
1341
1342 /**
1343 * Returns the source IP from a given flow rule if the rule contains
1344 * the match of it.
1345 *
1346 * @param flowRule flow rule
1347 * @return ip prefix, or null if the rule doesn't have ip match
1348 */
1349 private IpPrefix getSrcIpFromSelector(FlowRule flowRule) {
1350 Criterion criterion = flowRule.selector().getCriterion(IPV4_SRC);
1351 if (criterion != null && criterion instanceof IPCriterion) {
1352 IPCriterion ip = (IPCriterion) criterion;
1353 return ip.ip();
1354 } else {
1355 return null;
1356 }
1357 }
1358
1359 /**
1360 * Returns the group ID from a given flow rule if the rule contains the
1361 * treatment of it.
1362 *
1363 * @param flowRule flow rule
1364 * @return group id, or null if the rule doesn't have group instruction
1365 */
1366 private GroupId getGroupIdFromTreatment(FlowRule flowRule) {
1367 Instruction instruction = flowRule.treatment().allInstructions().stream()
1368 .filter(inst -> inst instanceof Instructions.GroupInstruction)
1369 .findFirst()
1370 .orElse(null);
1371
1372 if (instruction == null) {
1373 return null;
1374 }
1375
1376 return ((Instructions.GroupInstruction) instruction).groupId();
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001377 }
1378
1379 /**
Hyunsun Moond52bffc2016-01-29 18:57:05 -08001380 * Returns the output port number from a given flow rule.
1381 *
1382 * @param flowRule flow rule
1383 * @return port number, or null if the rule does not have output instruction
1384 */
1385 private PortNumber getOutputFromTreatment(FlowRule flowRule) {
1386 Instruction instruction = flowRule.treatment().allInstructions().stream()
Hyunsun Moon6d247342016-02-12 12:48:47 -08001387 .filter(inst -> inst instanceof Instructions.OutputInstruction)
Hyunsun Moond52bffc2016-01-29 18:57:05 -08001388 .findFirst()
1389 .orElse(null);
1390
1391 if (instruction == null) {
1392 return null;
1393 }
1394
1395 return ((Instructions.OutputInstruction) instruction).port();
1396 }
1397
1398 /**
Hyunsun Moon6d247342016-02-12 12:48:47 -08001399 * Returns if a given flow rule has vlan push instruction or not.
1400 *
1401 * @param flowRule flow rule
1402 * @return true if it includes vlan push, or false
1403 */
1404 private boolean isVlanPushFromTreatment(FlowRule flowRule) {
1405 Instruction instruction = flowRule.treatment().allInstructions().stream()
1406 .filter(inst -> inst instanceof L2ModificationInstruction)
1407 .filter(inst -> ((L2ModificationInstruction) inst).subtype().equals(VLAN_PUSH))
1408 .findAny()
1409 .orElse(null);
1410
1411 return instruction != null;
1412 }
1413
1414 /**
Hyunsun Moon4a915152016-01-14 16:56:26 -08001415 * Creates a new group for a given service.
1416 *
1417 * @param deviceId device id to create a group
1418 * @param service cord service
1419 * @return group id, or null if it fails to create
1420 */
1421 private GroupId createServiceGroup(DeviceId deviceId, CordService service) {
1422 checkNotNull(service);
1423
1424 GroupKey groupKey = getGroupKey(service.id());
1425 Group group = groupService.getGroup(deviceId, groupKey);
1426 GroupId groupId = getGroupId(service.id(), deviceId);
1427
1428 if (group != null) {
1429 log.debug("Group {} is already exist in {}", service.id(), deviceId);
1430 return groupId;
1431 }
1432
1433 GroupBuckets buckets = getServiceGroupBuckets(deviceId, service.segmentationId(), service.hosts());
1434 GroupDescription groupDescription = new DefaultGroupDescription(
1435 deviceId,
1436 GroupDescription.Type.SELECT,
1437 buckets,
1438 groupKey,
1439 groupId.id(),
1440 appId);
1441
1442 groupService.addGroup(groupDescription);
1443
1444 return groupId;
1445 }
1446
1447 /**
1448 * Returns group buckets for a given device.
1449 *
1450 * @param deviceId device id
1451 * @param tunnelId tunnel id
1452 * @param hosts list of host
1453 * @return group buckets
1454 */
1455 private GroupBuckets getServiceGroupBuckets(DeviceId deviceId, long tunnelId, Map<Host, IpAddress> hosts) {
1456 List<GroupBucket> buckets = Lists.newArrayList();
1457
1458 for (Map.Entry<Host, IpAddress> entry : hosts.entrySet()) {
1459 Host host = entry.getKey();
1460 Ip4Address remoteIp = entry.getValue().getIp4Address();
1461 DeviceId hostDevice = host.location().deviceId();
1462
1463 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
1464 .builder()
1465 .setEthDst(host.mac());
1466
1467 if (deviceId.equals(hostDevice)) {
1468 tBuilder.setOutput(host.location().port());
1469 } else {
1470 ExtensionTreatment tunnelDst = getTunnelDst(deviceId, remoteIp);
1471 if (tunnelDst == null) {
1472 continue;
1473 }
1474
1475 tBuilder.extension(tunnelDst, deviceId)
1476 .setTunnelId(tunnelId)
1477 .setOutput(getTunnelPort(hostDevice));
1478 }
1479
1480 buckets.add(DefaultGroupBucket.createSelectGroupBucket(tBuilder.build()));
1481 }
1482
1483 return new GroupBuckets(buckets);
1484 }
1485
1486 /**
1487 * Returns globally unique group ID.
1488 *
1489 * @param serviceId service id
1490 * @param deviceId device id
1491 * @return group id
1492 */
1493 private GroupId getGroupId(CordServiceId serviceId, DeviceId deviceId) {
1494 return new DefaultGroupId(Objects.hash(serviceId, deviceId));
1495 }
1496
1497 /**
1498 * Returns group key of a service.
1499 *
1500 * @param serviceId service id
1501 * @return group key
1502 */
1503 private GroupKey getGroupKey(CordServiceId serviceId) {
1504 return new DefaultGroupKey(serviceId.id().getBytes());
1505 }
1506
1507 /**
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001508 * Returns extension instruction to set tunnel destination.
1509 *
1510 * @param deviceId device id
1511 * @param remoteIp tunnel destination address
1512 * @return extension treatment or null if it fails to get instruction
1513 */
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001514 private ExtensionTreatment getTunnelDst(DeviceId deviceId, Ip4Address remoteIp) {
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001515 try {
1516 Driver driver = driverService.getDriver(deviceId);
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001517 DefaultDriverData driverData = new DefaultDriverData(driver, deviceId);
1518 DriverHandler handler = new DefaultDriverHandler(driverData);
1519 ExtensionTreatmentResolver resolver = handler.behaviour(ExtensionTreatmentResolver.class);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001520
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001521 ExtensionTreatment treatment =
1522 resolver.getExtensionInstruction(NICIRA_SET_TUNNEL_DST.type());
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001523 treatment.setPropertyValue("tunnelDst", remoteIp);
1524
1525 return treatment;
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001526 } catch (ItemNotFoundException | UnsupportedOperationException |
1527 ExtensionPropertyException e) {
1528 log.error("Failed to get extension instruction {}", deviceId);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001529 return null;
1530 }
1531 }
1532}
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001533