blob: 877ec30a39d6df3aa3770ada4e96b7f92833f843 [file] [log] [blame]
Hyunsun Moon05f528a2015-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 Moonba290072015-12-16 20:53:23 -080018import com.google.common.collect.Lists;
19import com.google.common.collect.Maps;
20import org.onlab.packet.Ethernet;
Hyunsun Moon3467a262016-01-14 16:56:26 -080021import org.onlab.packet.IPv4;
Hyunsun Moon05f528a2015-11-04 17:34:35 -080022import org.onlab.packet.Ip4Address;
Hyunsun Moonba290072015-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 Moon3467a262016-01-14 16:56:26 -080027import org.onlab.packet.TpPort;
Hyunsun Moon01556a52016-02-12 12:48:47 -080028import org.onlab.packet.VlanId;
Hyunsun Moon05f528a2015-11-04 17:34:35 -080029import org.onlab.util.ItemNotFoundException;
30import org.onosproject.core.ApplicationId;
Hyunsun Moonba290072015-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 Moon05f528a2015-11-04 17:34:35 -080035import org.onosproject.net.DeviceId;
Hyunsun Moonba290072015-12-16 20:53:23 -080036import org.onosproject.net.Host;
Hyunsun Moon2bf68e72016-01-15 11:41:14 -080037import org.onosproject.net.Port;
Hyunsun Moonba290072015-12-16 20:53:23 -080038import org.onosproject.net.PortNumber;
Hyunsun Moon05f528a2015-11-04 17:34:35 -080039import org.onosproject.net.behaviour.ExtensionTreatmentResolver;
Hyunsun Moonba290072015-12-16 20:53:23 -080040import org.onosproject.net.device.DeviceService;
Hyunsun Moon05f528a2015-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 Moonba290072015-12-16 20:53:23 -080046import org.onosproject.net.flow.DefaultFlowRule;
Hyunsun Moon05f528a2015-11-04 17:34:35 -080047import org.onosproject.net.flow.DefaultTrafficSelector;
48import org.onosproject.net.flow.DefaultTrafficTreatment;
Hyunsun Moonba290072015-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 Moon05f528a2015-11-04 17:34:35 -080053import org.onosproject.net.flow.TrafficSelector;
54import org.onosproject.net.flow.TrafficTreatment;
Hyunsun Moonba290072015-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 Moon05f528a2015-11-04 17:34:35 -080059import org.onosproject.net.flow.instructions.ExtensionPropertyException;
60import org.onosproject.net.flow.instructions.ExtensionTreatment;
Hyunsun Moonba290072015-12-16 20:53:23 -080061import org.onosproject.net.flow.instructions.Instruction;
62import org.onosproject.net.flow.instructions.Instructions;
Hyunsun Moon01556a52016-02-12 12:48:47 -080063import org.onosproject.net.flow.instructions.L2ModificationInstruction;
Hyunsun Moonba290072015-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;
74import org.onosproject.openstackswitching.OpenstackNetwork;
75import org.onosproject.openstackswitching.OpenstackSubnet;
Hyunsun Moon05f528a2015-11-04 17:34:35 -080076import org.slf4j.Logger;
77
Hyunsun Moonee37c442016-01-07 01:32:31 -080078import java.util.ArrayList;
Hyunsun Moon05f528a2015-11-04 17:34:35 -080079import java.util.List;
Hyunsun Moonba290072015-12-16 20:53:23 -080080import java.util.Map;
Hyunsun Moonba290072015-12-16 20:53:23 -080081import java.util.Objects;
82import java.util.Set;
83import java.util.stream.Collectors;
Hyunsun Moon05f528a2015-11-04 17:34:35 -080084
Hyunsun Moon05f528a2015-11-04 17:34:35 -080085import static com.google.common.base.Preconditions.checkNotNull;
Hyunsun Moonba290072015-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 Moon05f528a2015-11-04 17:34:35 -080090import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST;
Hyunsun Moonba290072015-12-16 20:53:23 -080091import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.ETH_DST;
Hyunsun Moon01556a52016-02-12 12:48:47 -080092import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.VLAN_PUSH;
Hyunsun Moon05f528a2015-11-04 17:34:35 -080093import static org.slf4j.LoggerFactory.getLogger;
94
95/**
Hyunsun Moonba290072015-12-16 20:53:23 -080096 * Populates rules for CORD VTN service.
Hyunsun Moon05f528a2015-11-04 17:34:35 -080097 */
Hyunsun Moonba290072015-12-16 20:53:23 -080098public class CordVtnRuleInstaller {
99
Hyunsun Moon05f528a2015-11-04 17:34:35 -0800100 protected final Logger log = getLogger(getClass());
101
Hyunsun Moon3467a262016-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 Moon01556a52016-02-12 12:48:47 -0800108 private static final int TABLE_Q_IN_Q = 6;
Hyunsun Moonba290072015-12-16 20:53:23 -0800109
Hyunsun Moon64ec6142016-01-29 18:57:05 -0800110 private static final int MANAGEMENT_PRIORITY = 55000;
Hyunsun Moon01556a52016-02-12 12:48:47 -0800111 private static final int VSG_PRIORITY = 55000;
Hyunsun Moon64ec6142016-01-29 18:57:05 -0800112 private static final int HIGH_PRIORITY = 50000;
Hyunsun Moon05f528a2015-11-04 17:34:35 -0800113 private static final int DEFAULT_PRIORITY = 5000;
Hyunsun Moon64ec6142016-01-29 18:57:05 -0800114 private static final int LOW_PRIORITY = 4000;
Hyunsun Moonba290072015-12-16 20:53:23 -0800115 private static final int LOWEST_PRIORITY = 0;
Hyunsun Moon3467a262016-01-14 16:56:26 -0800116
117 private static final int VXLAN_UDP_PORT = 4789;
Hyunsun Moon01556a52016-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 Moon05f528a2015-11-04 17:34:35 -0800123
124 private final ApplicationId appId;
Hyunsun Moonba290072015-12-16 20:53:23 -0800125 private final FlowRuleService flowRuleService;
126 private final DeviceService deviceService;
Hyunsun Moon05f528a2015-11-04 17:34:35 -0800127 private final DriverService driverService;
Hyunsun Moonba290072015-12-16 20:53:23 -0800128 private final GroupService groupService;
129 private final MastershipService mastershipService;
Hyunsun Moon05f528a2015-11-04 17:34:35 -0800130 private final String tunnelType;
131
132 /**
Hyunsun Moonba290072015-12-16 20:53:23 -0800133 * Creates a new rule populator.
Hyunsun Moon05f528a2015-11-04 17:34:35 -0800134 *
135 * @param appId application id
Hyunsun Moonba290072015-12-16 20:53:23 -0800136 * @param flowRuleService flow rule service
137 * @param deviceService device service
Hyunsun Moon05f528a2015-11-04 17:34:35 -0800138 * @param driverService driver service
Jian Li248e9202016-01-22 16:46:58 -0800139 * @param groupService group service
140 * @param mastershipService mastership service
Hyunsun Moon05f528a2015-11-04 17:34:35 -0800141 * @param tunnelType tunnel type
142 */
143 public CordVtnRuleInstaller(ApplicationId appId,
Hyunsun Moonba290072015-12-16 20:53:23 -0800144 FlowRuleService flowRuleService,
145 DeviceService deviceService,
Hyunsun Moon05f528a2015-11-04 17:34:35 -0800146 DriverService driverService,
Hyunsun Moonba290072015-12-16 20:53:23 -0800147 GroupService groupService,
148 MastershipService mastershipService,
Hyunsun Moon05f528a2015-11-04 17:34:35 -0800149 String tunnelType) {
150 this.appId = appId;
Hyunsun Moonba290072015-12-16 20:53:23 -0800151 this.flowRuleService = flowRuleService;
152 this.deviceService = deviceService;
Hyunsun Moon05f528a2015-11-04 17:34:35 -0800153 this.driverService = driverService;
Hyunsun Moonba290072015-12-16 20:53:23 -0800154 this.groupService = groupService;
155 this.mastershipService = mastershipService;
Hyunsun Moon05f528a2015-11-04 17:34:35 -0800156 this.tunnelType = checkNotNull(tunnelType);
157 }
158
159 /**
Hyunsun Moonba290072015-12-16 20:53:23 -0800160 * Installs table miss rule to a give device.
Hyunsun Moon05f528a2015-11-04 17:34:35 -0800161 *
Hyunsun Moonba290072015-12-16 20:53:23 -0800162 * @param deviceId device id to install the rules
Hyunsun Moon126171d2016-02-09 01:55:48 -0800163 * @param dpIntf data plane interface name
164 * @param dpIp data plane ip address
Hyunsun Moon05f528a2015-11-04 17:34:35 -0800165 */
Hyunsun Moon126171d2016-02-09 01:55:48 -0800166 public void init(DeviceId deviceId, String dpIntf, IpAddress dpIp) {
Hyunsun Moonba290072015-12-16 20:53:23 -0800167 // default is drop packets which can be accomplished without
168 // a table miss entry for all table.
Hyunsun Moon3467a262016-01-14 16:56:26 -0800169 PortNumber tunnelPort = getTunnelPort(deviceId);
Hyunsun Moon126171d2016-02-09 01:55:48 -0800170 PortNumber dpPort = getDpPort(deviceId, dpIntf);
Hyunsun Moon3467a262016-01-14 16:56:26 -0800171
Hyunsun Moon126171d2016-02-09 01:55:48 -0800172 processFirstTable(deviceId, dpPort, dpIp);
173 processInPortTable(deviceId, tunnelPort, dpPort);
174 processAccessTypeTable(deviceId, dpPort);
Hyunsun Moon01556a52016-02-12 12:48:47 -0800175 processQInQTable(deviceId, dpPort);
Hyunsun Moon05f528a2015-11-04 17:34:35 -0800176 }
177
178 /**
Hyunsun Moonba290072015-12-16 20:53:23 -0800179 * Populates basic rules that connect a VM to the other VMs in the system.
Hyunsun Moon05f528a2015-11-04 17:34:35 -0800180 *
Hyunsun Moonba290072015-12-16 20:53:23 -0800181 * @param host host
Hyunsun Moonba290072015-12-16 20:53:23 -0800182 * @param tunnelIp tunnel ip
183 * @param vNet openstack network
Hyunsun Moon05f528a2015-11-04 17:34:35 -0800184 */
Hyunsun Mooncb799442016-01-15 20:03:18 -0800185 public void populateBasicConnectionRules(Host host, IpAddress tunnelIp, OpenstackNetwork vNet) {
Hyunsun Moonba290072015-12-16 20:53:23 -0800186 checkNotNull(host);
187 checkNotNull(vNet);
Hyunsun Moon05f528a2015-11-04 17:34:35 -0800188
Hyunsun Moonba290072015-12-16 20:53:23 -0800189 DeviceId deviceId = host.location().deviceId();
190 if (!mastershipService.isLocalMaster(deviceId)) {
191 return;
Hyunsun Moon05f528a2015-11-04 17:34:35 -0800192 }
193
Hyunsun Moonba290072015-12-16 20:53:23 -0800194 PortNumber inPort = host.location().port();
195 MacAddress dstMac = host.mac();
Hyunsun Mooncb799442016-01-15 20:03:18 -0800196 IpAddress hostIp = host.ipAddresses().stream().findFirst().get();
Hyunsun Moonba290072015-12-16 20:53:23 -0800197 long tunnelId = Long.parseLong(vNet.segmentId());
Hyunsun Moon05f528a2015-11-04 17:34:35 -0800198
Hyunsun Moonba290072015-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 Moon1257efc2016-02-01 23:00:56 -0800210 populateServiceIsolationRule(Ip4Prefix.valueOf(subnet.cidr()));
Hyunsun Moonba290072015-12-16 20:53:23 -0800211 populateDstIpRule(deviceId, inPort, dstMac, hostIp, tunnelId, tunnelIp);
212 populateTunnelInRule(deviceId, inPort, dstMac, tunnelId);
Hyunsun Moon05f528a2015-11-04 17:34:35 -0800213 }
214
215 /**
Hyunsun Moonba290072015-12-16 20:53:23 -0800216 * Removes basic rules related to a given flow information.
217 *
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 }
239 }
240
241 MacAddress dstMac = getDstMacFromTreatment(flowRule);
242 if (dstMac != null && dstMac.equals(mac)) {
243 processFlowRule(false, flowRule);
244 continue;
245 }
246
247 dstMac = getDstMacFromSelector(flowRule);
248 if (dstMac != null && dstMac.equals(mac)) {
249 processFlowRule(false, flowRule);
250 continue;
251 }
252
253 IpPrefix dstIp = getDstIpFromSelector(flowRule);
254 if (dstIp != null && dstIp.equals(ip.toIpPrefix())) {
255 processFlowRule(false, flowRule);
256 }
Hyunsun Moonba290072015-12-16 20:53:23 -0800257 }
258
259 // TODO uninstall same network access rule in access table if no vm exists in the network
260 }
261
262 /**
Hyunsun Moonee37c442016-01-07 01:32:31 -0800263 * Populates service dependency rules.
264 *
265 * @param tService tenant cord service
266 * @param pService provider cord service
Hyunsun Moon5f7ed8a2016-02-10 17:02:37 -0800267 * @param isBidirectional true to enable bidirectional connection between two services
Hyunsun Moonee37c442016-01-07 01:32:31 -0800268 */
Hyunsun Moon5f7ed8a2016-02-10 17:02:37 -0800269 public void populateServiceDependencyRules(CordService tService, CordService pService,
270 boolean isBidirectional) {
Hyunsun Moonee37c442016-01-07 01:32:31 -0800271 checkNotNull(tService);
272 checkNotNull(pService);
273
274 Ip4Prefix srcRange = tService.serviceIpRange().getIp4Prefix();
275 Ip4Prefix dstRange = pService.serviceIpRange().getIp4Prefix();
276 Ip4Address serviceIp = pService.serviceIp().getIp4Address();
277
278 Map<DeviceId, GroupId> outGroups = Maps.newHashMap();
279 Map<DeviceId, Set<PortNumber>> inPorts = Maps.newHashMap();
280
281 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
282 GroupId groupId = createServiceGroup(device.id(), pService);
283 outGroups.put(device.id(), groupId);
284
285 Set<PortNumber> vms = tService.hosts().keySet()
286 .stream()
287 .filter(host -> host.location().deviceId().equals(device.id()))
288 .map(host -> host.location().port())
289 .collect(Collectors.toSet());
290 inPorts.put(device.id(), vms);
291 }
292
293 populateIndirectAccessRule(srcRange, serviceIp, outGroups);
294 populateDirectAccessRule(srcRange, dstRange);
Hyunsun Moon5f7ed8a2016-02-10 17:02:37 -0800295 if (isBidirectional) {
296 populateDirectAccessRule(dstRange, srcRange);
297 }
Hyunsun Moonee37c442016-01-07 01:32:31 -0800298 populateInServiceRule(inPorts, outGroups);
299 }
300
301 /**
Hyunsun Moonba290072015-12-16 20:53:23 -0800302 * Removes service dependency rules.
303 *
304 * @param tService tenant cord service
305 * @param pService provider cord service
306 */
307 public void removeServiceDependencyRules(CordService tService, CordService pService) {
308 checkNotNull(tService);
309 checkNotNull(pService);
310
311 Ip4Prefix srcRange = tService.serviceIpRange().getIp4Prefix();
312 Ip4Prefix dstRange = pService.serviceIpRange().getIp4Prefix();
313 IpPrefix serviceIp = pService.serviceIp().toIpPrefix();
314
315 Map<DeviceId, GroupId> outGroups = Maps.newHashMap();
316 GroupKey groupKey = new DefaultGroupKey(pService.id().id().getBytes());
317
318 deviceService.getAvailableDevices(SWITCH).forEach(device -> {
319 Group group = groupService.getGroup(device.id(), groupKey);
320 if (group != null) {
321 outGroups.put(device.id(), group.id());
322 }
323 });
324
325 for (FlowRule flowRule : flowRuleService.getFlowRulesById(appId)) {
326 IpPrefix dstIp = getDstIpFromSelector(flowRule);
327 IpPrefix srcIp = getSrcIpFromSelector(flowRule);
328
329 if (dstIp != null && dstIp.equals(serviceIp)) {
330 processFlowRule(false, flowRule);
331 continue;
332 }
333
334 if (dstIp != null && srcIp != null) {
335 if (dstIp.equals(dstRange) && srcIp.equals(srcRange)) {
336 processFlowRule(false, flowRule);
337 continue;
338 }
339
340 if (dstIp.equals(srcRange) && srcIp.equals(dstRange)) {
341 processFlowRule(false, flowRule);
342 continue;
343 }
344 }
345
346 GroupId groupId = getGroupIdFromTreatment(flowRule);
347 if (groupId != null && groupId.equals(outGroups.get(flowRule.deviceId()))) {
348 processFlowRule(false, flowRule);
349 }
350 }
351
352 // TODO remove the group if it is not in use
353 }
354
355 /**
Hyunsun Moonee37c442016-01-07 01:32:31 -0800356 * Updates group buckets for a given service to all devices.
357 *
358 * @param service cord service
359 */
360 public void updateServiceGroup(CordService service) {
361 checkNotNull(service);
362
363 GroupKey groupKey = getGroupKey(service.id());
364
365 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
366 DeviceId deviceId = device.id();
367 if (!mastershipService.isLocalMaster(deviceId)) {
368 continue;
369 }
370
371 Group group = groupService.getGroup(deviceId, groupKey);
372 if (group == null) {
Hyunsun Mooncb799442016-01-15 20:03:18 -0800373 log.trace("No group exists for service {} in {}, do nothing.", service.id(), deviceId);
Hyunsun Moonee37c442016-01-07 01:32:31 -0800374 continue;
375 }
376
377 List<GroupBucket> oldBuckets = group.buckets().buckets();
378 List<GroupBucket> newBuckets = getServiceGroupBuckets(
379 deviceId, service.segmentationId(), service.hosts()).buckets();
380
381 if (oldBuckets.equals(newBuckets)) {
382 continue;
383 }
384
385 List<GroupBucket> bucketsToRemove = new ArrayList<>(oldBuckets);
386 bucketsToRemove.removeAll(newBuckets);
387 if (!bucketsToRemove.isEmpty()) {
388 groupService.removeBucketsFromGroup(
389 deviceId,
390 groupKey,
391 new GroupBuckets(bucketsToRemove),
392 groupKey, appId);
393 }
394
395 List<GroupBucket> bucketsToAdd = new ArrayList<>(newBuckets);
396 bucketsToAdd.removeAll(oldBuckets);
397 if (!bucketsToAdd.isEmpty()) {
398 groupService.addBucketsToGroup(
399 deviceId,
400 groupKey,
401 new GroupBuckets(bucketsToAdd),
402 groupKey, appId);
403 }
404 }
405 }
406
407 /**
Hyunsun Moon64ec6142016-01-29 18:57:05 -0800408 * Populates flow rules for management network access.
409 *
410 * @param host host which has management network interface
411 * @param mService management network service
412 */
413 public void populateManagementNetworkRules(Host host, CordService mService) {
414 checkNotNull(mService);
415
416 DeviceId deviceId = host.location().deviceId();
417 IpAddress hostIp = host.ipAddresses().stream().findFirst().get();
418
Hyunsun Moon01556a52016-02-12 12:48:47 -0800419 if (!mastershipService.isLocalMaster(deviceId)) {
420 return;
421 }
422
Hyunsun Moon64ec6142016-01-29 18:57:05 -0800423 TrafficSelector selector = DefaultTrafficSelector.builder()
424 .matchEthType(Ethernet.TYPE_ARP)
425 .matchArpTpa(mService.serviceIp().getIp4Address())
426 .build();
427
428 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
429 .setOutput(PortNumber.LOCAL)
430 .build();
431
432 FlowRule flowRule = DefaultFlowRule.builder()
433 .fromApp(appId)
434 .withSelector(selector)
435 .withTreatment(treatment)
436 .withPriority(MANAGEMENT_PRIORITY)
437 .forDevice(deviceId)
438 .forTable(TABLE_FIRST)
439 .makePermanent()
440 .build();
441
442 processFlowRule(true, flowRule);
443
444 selector = DefaultTrafficSelector.builder()
445 .matchInPort(PortNumber.LOCAL)
446 .matchEthType(Ethernet.TYPE_ARP)
447 .matchArpTpa(hostIp.getIp4Address())
448 .build();
449
450 treatment = DefaultTrafficTreatment.builder()
451 .setOutput(host.location().port())
452 .build();
453
454 flowRule = DefaultFlowRule.builder()
455 .fromApp(appId)
456 .withSelector(selector)
457 .withTreatment(treatment)
458 .withPriority(MANAGEMENT_PRIORITY)
459 .forDevice(deviceId)
460 .forTable(TABLE_FIRST)
461 .makePermanent()
462 .build();
463
464 processFlowRule(true, flowRule);
465
466 selector = DefaultTrafficSelector.builder()
467 .matchInPort(PortNumber.LOCAL)
468 .matchEthType(Ethernet.TYPE_IPV4)
469 .matchIPDst(mService.serviceIpRange())
470 .build();
471
472 treatment = DefaultTrafficTreatment.builder()
473 .transition(TABLE_DST_IP)
474 .build();
475
476 flowRule = DefaultFlowRule.builder()
477 .fromApp(appId)
478 .withSelector(selector)
479 .withTreatment(treatment)
480 .withPriority(MANAGEMENT_PRIORITY)
481 .forDevice(deviceId)
482 .forTable(TABLE_FIRST)
483 .makePermanent()
484 .build();
485
486 processFlowRule(true, flowRule);
487
488 selector = DefaultTrafficSelector.builder()
489 .matchEthType(Ethernet.TYPE_IPV4)
490 .matchIPDst(mService.serviceIp().toIpPrefix())
491 .build();
492
493 treatment = DefaultTrafficTreatment.builder()
494 .setOutput(PortNumber.LOCAL)
495 .build();
496
497 flowRule = DefaultFlowRule.builder()
498 .fromApp(appId)
499 .withSelector(selector)
500 .withTreatment(treatment)
501 .withPriority(MANAGEMENT_PRIORITY)
502 .forDevice(deviceId)
503 .forTable(TABLE_ACCESS_TYPE)
504 .makePermanent()
505 .build();
506
507 processFlowRule(true, flowRule);
508 }
509
510 /**
511 * Removes management network access rules.
512 *
513 * @param host host to be removed
514 * @param mService service for management network
515 */
516 public void removeManagementNetworkRules(Host host, CordService mService) {
517 checkNotNull(mService);
518
Hyunsun Moon01556a52016-02-12 12:48:47 -0800519 if (!mastershipService.isLocalMaster(host.location().deviceId())) {
520 return;
521 }
522
Hyunsun Moon64ec6142016-01-29 18:57:05 -0800523 for (FlowRule flowRule : flowRuleService.getFlowRulesById(appId)) {
524 if (flowRule.deviceId().equals(host.location().deviceId())) {
525 PortNumber port = getOutputFromTreatment(flowRule);
526 if (port != null && port.equals(host.location().port())) {
527 processFlowRule(false, flowRule);
528 }
529 }
530
531 // TODO remove the other rules if mgmt network is not in use
532 }
533 }
534
535 /**
Hyunsun Moon01556a52016-02-12 12:48:47 -0800536 * Populates rules for vSG VM.
537 *
538 * @param vSgHost vSG host
539 * @param vSgIps set of ip addresses of vSGs running inside the vSG VM
540 */
541 public void populateSubscriberGatewayRules(Host vSgHost, Set<IpAddress> vSgIps) {
542 VlanId serviceVlan = getServiceVlan(vSgHost);
543 PortNumber dpPort = getDpPort(vSgHost);
544
545 if (serviceVlan == null || dpPort == null) {
546 log.warn("Failed to populate rules for vSG VM {}", vSgHost.id());
547 return;
548 }
549
550 // for traffics with s-tag, strip the tag and take through the vSG VM
551 TrafficSelector selector = DefaultTrafficSelector.builder()
552 .matchVlanId(serviceVlan)
553 .build();
554
555 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
556 .popVlan()
557 .setOutput(vSgHost.location().port())
558 .build();
559
560 FlowRule flowRule = DefaultFlowRule.builder()
561 .fromApp(appId)
562 .withSelector(selector)
563 .withTreatment(treatment)
564 .withPriority(DEFAULT_PRIORITY)
565 .forDevice(vSgHost.location().deviceId())
566 .forTable(TABLE_Q_IN_Q)
567 .makePermanent()
568 .build();
569
570 processFlowRule(true, flowRule);
571
572 // for traffics with customer vlan, tag with the service vlan based on input port with
573 // lower priority to avoid conflict with WAN tag
574 selector = DefaultTrafficSelector.builder()
575 .matchInPort(vSgHost.location().port())
576 .build();
577
578 treatment = DefaultTrafficTreatment.builder()
579 .pushVlan()
580 .setVlanId(serviceVlan)
581 .setOutput(dpPort)
582 .build();
583
584 flowRule = DefaultFlowRule.builder()
585 .fromApp(appId)
586 .withSelector(selector)
587 .withTreatment(treatment)
588 .withPriority(LOW_PRIORITY)
589 .forDevice(vSgHost.location().deviceId())
590 .forTable(TABLE_Q_IN_Q)
591 .makePermanent()
592 .build();
593
594 processFlowRule(true, flowRule);
595
596 // for traffic coming from WAN, tag 500 and take through the vSG VM
597 // based on destination ip
598 vSgIps.stream().forEach(ip -> {
599 TrafficSelector downstream = DefaultTrafficSelector.builder()
600 .matchEthType(Ethernet.TYPE_IPV4)
601 .matchIPDst(ip.toIpPrefix())
602 .build();
603
604 TrafficTreatment downstreamTreatment = DefaultTrafficTreatment.builder()
605 .pushVlan()
606 .setVlanId(VLAN_WAN)
607 .setEthDst(vSgHost.mac())
608 .setOutput(vSgHost.location().port())
609 .build();
610
611 FlowRule downstreamFlowRule = DefaultFlowRule.builder()
612 .fromApp(appId)
613 .withSelector(downstream)
614 .withTreatment(downstreamTreatment)
615 .withPriority(DEFAULT_PRIORITY)
616 .forDevice(vSgHost.location().deviceId())
617 .forTable(TABLE_DST_IP)
618 .makePermanent()
619 .build();
620
621 processFlowRule(true, downstreamFlowRule);
622 });
623
624 // remove downstream flow rules for the vSG not shown in vSgIps
625 for (FlowRule rule : flowRuleService.getFlowRulesById(appId)) {
626 if (!rule.deviceId().equals(vSgHost.location().deviceId())) {
627 continue;
628 }
629 PortNumber output = getOutputFromTreatment(rule);
630 if (output == null || !output.equals(vSgHost.location().port()) ||
631 !isVlanPushFromTreatment(rule)) {
632 continue;
633 }
634
635 IpPrefix dstIp = getDstIpFromSelector(rule);
636 if (dstIp != null && !vSgIps.contains(dstIp.address())) {
637 processFlowRule(false, rule);
638 }
639 }
640 }
641
642 /**
Hyunsun Moon3467a262016-01-14 16:56:26 -0800643 * Populates default rules on the first table.
Hyunsun Moon126171d2016-02-09 01:55:48 -0800644 * It includes the rules for shuttling vxlan-encapped packets between ovs and
645 * linux stack,and external network connectivity.
Hyunsun Moonba290072015-12-16 20:53:23 -0800646 *
647 * @param deviceId device id
Hyunsun Moon126171d2016-02-09 01:55:48 -0800648 * @param dpPort data plane interface port number
649 * @param dpIp data plane ip address
Hyunsun Moonba290072015-12-16 20:53:23 -0800650 */
Hyunsun Moon126171d2016-02-09 01:55:48 -0800651 private void processFirstTable(DeviceId deviceId, PortNumber dpPort, IpAddress dpIp) {
Hyunsun Moon3467a262016-01-14 16:56:26 -0800652 // take vxlan packet out onto the physical port
653 TrafficSelector selector = DefaultTrafficSelector.builder()
654 .matchInPort(PortNumber.LOCAL)
655 .build();
Hyunsun Moonba290072015-12-16 20:53:23 -0800656
Hyunsun Moon3467a262016-01-14 16:56:26 -0800657 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Hyunsun Moon126171d2016-02-09 01:55:48 -0800658 .setOutput(dpPort)
Hyunsun Moon3467a262016-01-14 16:56:26 -0800659 .build();
Hyunsun Moonba290072015-12-16 20:53:23 -0800660
Hyunsun Moon3467a262016-01-14 16:56:26 -0800661 FlowRule flowRule = DefaultFlowRule.builder()
662 .fromApp(appId)
663 .withSelector(selector)
664 .withTreatment(treatment)
Hyunsun Moon64ec6142016-01-29 18:57:05 -0800665 .withPriority(HIGH_PRIORITY)
Hyunsun Moon3467a262016-01-14 16:56:26 -0800666 .forDevice(deviceId)
667 .forTable(TABLE_FIRST)
668 .makePermanent()
669 .build();
Hyunsun Moonba290072015-12-16 20:53:23 -0800670
Hyunsun Moon3467a262016-01-14 16:56:26 -0800671 processFlowRule(true, flowRule);
Hyunsun Moonba290072015-12-16 20:53:23 -0800672
Hyunsun Moon3467a262016-01-14 16:56:26 -0800673 // take a vxlan encap'd packet through the Linux stack
674 selector = DefaultTrafficSelector.builder()
Hyunsun Moon126171d2016-02-09 01:55:48 -0800675 .matchInPort(dpPort)
Hyunsun Moon3467a262016-01-14 16:56:26 -0800676 .matchEthType(Ethernet.TYPE_IPV4)
677 .matchIPProtocol(IPv4.PROTOCOL_UDP)
678 .matchUdpDst(TpPort.tpPort(VXLAN_UDP_PORT))
679 .build();
Hyunsun Moonba290072015-12-16 20:53:23 -0800680
Hyunsun Moon3467a262016-01-14 16:56:26 -0800681 treatment = DefaultTrafficTreatment.builder()
682 .setOutput(PortNumber.LOCAL)
683 .build();
Hyunsun Moonba290072015-12-16 20:53:23 -0800684
Hyunsun Moon3467a262016-01-14 16:56:26 -0800685 flowRule = DefaultFlowRule.builder()
686 .fromApp(appId)
687 .withSelector(selector)
688 .withTreatment(treatment)
Hyunsun Moon64ec6142016-01-29 18:57:05 -0800689 .withPriority(HIGH_PRIORITY)
Hyunsun Moon3467a262016-01-14 16:56:26 -0800690 .forDevice(deviceId)
691 .forTable(TABLE_FIRST)
692 .makePermanent()
693 .build();
694
695 processFlowRule(true, flowRule);
696
Hyunsun Moon126171d2016-02-09 01:55:48 -0800697 // take a packet to the data plane ip through Linux stack
Hyunsun Moon6dbd34b2016-01-15 20:11:41 -0800698 selector = DefaultTrafficSelector.builder()
Hyunsun Moon126171d2016-02-09 01:55:48 -0800699 .matchInPort(dpPort)
Hyunsun Moon6dbd34b2016-01-15 20:11:41 -0800700 .matchEthType(Ethernet.TYPE_IPV4)
Hyunsun Moon126171d2016-02-09 01:55:48 -0800701 .matchIPDst(dpIp.toIpPrefix())
Hyunsun Moon6dbd34b2016-01-15 20:11:41 -0800702 .build();
703
704 treatment = DefaultTrafficTreatment.builder()
705 .setOutput(PortNumber.LOCAL)
706 .build();
707
708 flowRule = DefaultFlowRule.builder()
709 .fromApp(appId)
710 .withSelector(selector)
711 .withTreatment(treatment)
Hyunsun Moon64ec6142016-01-29 18:57:05 -0800712 .withPriority(HIGH_PRIORITY)
Hyunsun Moon6dbd34b2016-01-15 20:11:41 -0800713 .forDevice(deviceId)
714 .forTable(TABLE_FIRST)
715 .makePermanent()
716 .build();
717
718 processFlowRule(true, flowRule);
719
720 // take an arp packet from physical through Linux stack
721 selector = DefaultTrafficSelector.builder()
Hyunsun Moon126171d2016-02-09 01:55:48 -0800722 .matchInPort(dpPort)
Hyunsun Moon6dbd34b2016-01-15 20:11:41 -0800723 .matchEthType(Ethernet.TYPE_ARP)
Hyunsun Moon01556a52016-02-12 12:48:47 -0800724 .matchArpTpa(dpIp.getIp4Address())
Hyunsun Moon6dbd34b2016-01-15 20:11:41 -0800725 .build();
726
727 treatment = DefaultTrafficTreatment.builder()
728 .setOutput(PortNumber.LOCAL)
729 .build();
730
731 flowRule = DefaultFlowRule.builder()
732 .fromApp(appId)
733 .withSelector(selector)
734 .withTreatment(treatment)
Hyunsun Moon64ec6142016-01-29 18:57:05 -0800735 .withPriority(HIGH_PRIORITY)
Hyunsun Moon6dbd34b2016-01-15 20:11:41 -0800736 .forDevice(deviceId)
737 .forTable(TABLE_FIRST)
738 .makePermanent()
739 .build();
740
741 processFlowRule(true, flowRule);
742
Hyunsun Moon3467a262016-01-14 16:56:26 -0800743 // take all else to the next table
744 selector = DefaultTrafficSelector.builder()
745 .build();
746
747 treatment = DefaultTrafficTreatment.builder()
748 .transition(TABLE_IN_PORT)
749 .build();
750
751 flowRule = DefaultFlowRule.builder()
752 .fromApp(appId)
753 .withSelector(selector)
754 .withTreatment(treatment)
755 .withPriority(LOWEST_PRIORITY)
756 .forDevice(deviceId)
757 .forTable(TABLE_FIRST)
758 .makePermanent()
759 .build();
760
761 processFlowRule(true, flowRule);
Hyunsun Moon01556a52016-02-12 12:48:47 -0800762
763 // take all vlan tagged packet to the Q_IN_Q table
764 selector = DefaultTrafficSelector.builder()
765 .matchVlanId(VlanId.ANY)
766 .build();
767
768 treatment = DefaultTrafficTreatment.builder()
769 .transition(TABLE_Q_IN_Q)
770 .build();
771
772 flowRule = DefaultFlowRule.builder()
773 .fromApp(appId)
774 .withSelector(selector)
775 .withTreatment(treatment)
776 .withPriority(VSG_PRIORITY)
777 .forDevice(deviceId)
778 .forTable(TABLE_FIRST)
779 .makePermanent()
780 .build();
781
782 processFlowRule(true, flowRule);
Hyunsun Moonba290072015-12-16 20:53:23 -0800783 }
784
785 /**
Hyunsun Moon126171d2016-02-09 01:55:48 -0800786 * Forward table miss packets in ACCESS_TYPE table to data plane port.
Hyunsun Moonba290072015-12-16 20:53:23 -0800787 *
788 * @param deviceId device id
Hyunsun Moon126171d2016-02-09 01:55:48 -0800789 * @param dpPort data plane interface port number
Hyunsun Moonba290072015-12-16 20:53:23 -0800790 */
Hyunsun Moon126171d2016-02-09 01:55:48 -0800791 private void processAccessTypeTable(DeviceId deviceId, PortNumber dpPort) {
Hyunsun Moonba290072015-12-16 20:53:23 -0800792 TrafficSelector selector = DefaultTrafficSelector.builder()
793 .build();
794
795 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Hyunsun Moon126171d2016-02-09 01:55:48 -0800796 .setOutput(dpPort)
Hyunsun Moonba290072015-12-16 20:53:23 -0800797 .build();
798
799 FlowRule flowRule = DefaultFlowRule.builder()
800 .fromApp(appId)
801 .withSelector(selector)
802 .withTreatment(treatment)
803 .withPriority(LOWEST_PRIORITY)
804 .forDevice(deviceId)
805 .forTable(TABLE_ACCESS_TYPE)
806 .makePermanent()
807 .build();
808
809 processFlowRule(true, flowRule);
810 }
811
812 /**
Hyunsun Moon3467a262016-01-14 16:56:26 -0800813 * Populates default rules for IN_PORT table.
814 * All packets from tunnel port are forwarded to TUNNEL_ID table and all packets
Hyunsun Moon126171d2016-02-09 01:55:48 -0800815 * from data plane interface port to ACCESS_TYPE table.
Hyunsun Moonba290072015-12-16 20:53:23 -0800816 *
817 * @param deviceId device id to install the rules
Hyunsun Moon3467a262016-01-14 16:56:26 -0800818 * @param tunnelPort tunnel port number
Hyunsun Moon126171d2016-02-09 01:55:48 -0800819 * @param dpPort data plane interface port number
Hyunsun Moonba290072015-12-16 20:53:23 -0800820 */
Hyunsun Moon126171d2016-02-09 01:55:48 -0800821 private void processInPortTable(DeviceId deviceId, PortNumber tunnelPort, PortNumber dpPort) {
Hyunsun Moonba290072015-12-16 20:53:23 -0800822 checkNotNull(tunnelPort);
823
824 TrafficSelector selector = DefaultTrafficSelector.builder()
825 .matchInPort(tunnelPort)
826 .build();
Hyunsun Moon3467a262016-01-14 16:56:26 -0800827
Hyunsun Moonba290072015-12-16 20:53:23 -0800828 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
829 .transition(TABLE_TUNNEL_IN)
830 .build();
831
832 FlowRule flowRule = DefaultFlowRule.builder()
833 .fromApp(appId)
834 .withSelector(selector)
835 .withTreatment(treatment)
836 .withPriority(DEFAULT_PRIORITY)
837 .forDevice(deviceId)
838 .forTable(TABLE_IN_PORT)
839 .makePermanent()
840 .build();
841
842 processFlowRule(true, flowRule);
Hyunsun Moon3467a262016-01-14 16:56:26 -0800843
844 selector = DefaultTrafficSelector.builder()
Hyunsun Moon126171d2016-02-09 01:55:48 -0800845 .matchInPort(dpPort)
Hyunsun Moon3467a262016-01-14 16:56:26 -0800846 .build();
847
848 treatment = DefaultTrafficTreatment.builder()
849 .transition(TABLE_DST_IP)
850 .build();
851
852 flowRule = DefaultFlowRule.builder()
853 .fromApp(appId)
854 .withSelector(selector)
855 .withTreatment(treatment)
856 .withPriority(DEFAULT_PRIORITY)
857 .forDevice(deviceId)
858 .forTable(TABLE_IN_PORT)
859 .makePermanent()
860 .build();
861
862 processFlowRule(true, flowRule);
Hyunsun Moonba290072015-12-16 20:53:23 -0800863 }
864
865 /**
Hyunsun Moon01556a52016-02-12 12:48:47 -0800866 * Populates default rules for Q_IN_Q table.
867 *
868 * @param deviceId device id
869 * @param dpPort data plane interface port number
870 */
871 private void processQInQTable(DeviceId deviceId, PortNumber dpPort) {
872 // for traffic going out to WAN, strip vid 500 and take through data plane interface
873 TrafficSelector selector = DefaultTrafficSelector.builder()
874 .matchVlanId(VLAN_WAN)
875 .build();
876
877 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
878 .popVlan()
879 .setOutput(dpPort)
880 .build();
881
882 FlowRule flowRule = DefaultFlowRule.builder()
883 .fromApp(appId)
884 .withSelector(selector)
885 .withTreatment(treatment)
886 .withPriority(DEFAULT_PRIORITY)
887 .forDevice(deviceId)
888 .forTable(TABLE_Q_IN_Q)
889 .makePermanent()
890 .build();
891
892 processFlowRule(true, flowRule);
893
894 selector = DefaultTrafficSelector.builder()
895 .matchVlanId(VLAN_WAN)
896 .matchEthType(Ethernet.TYPE_ARP)
897 .build();
898
899 treatment = DefaultTrafficTreatment.builder()
900 .setOutput(PortNumber.CONTROLLER)
901 .build();
902
903 flowRule = DefaultFlowRule.builder()
904 .fromApp(appId)
905 .withSelector(selector)
906 .withTreatment(treatment)
907 .withPriority(HIGH_PRIORITY)
908 .forDevice(deviceId)
909 .forTable(TABLE_Q_IN_Q)
910 .makePermanent()
911 .build();
912
913 processFlowRule(true, flowRule);
914 }
915
916 /**
Hyunsun Moonba290072015-12-16 20:53:23 -0800917 * Populates rules for local in port in IN_PORT table.
918 * Flows from a given in port, whose source IP is service IP transition
919 * to DST_TYPE table. Other flows transition to IN_SERVICE table.
920 *
921 * @param deviceId device id to install the rules
922 * @param inPort in port
923 * @param srcIp source ip
924 */
925 private void populateLocalInPortRule(DeviceId deviceId, PortNumber inPort, IpAddress srcIp) {
926 TrafficSelector selector = DefaultTrafficSelector.builder()
927 .matchInPort(inPort)
928 .matchEthType(Ethernet.TYPE_IPV4)
929 .matchIPSrc(srcIp.toIpPrefix())
930 .build();
Hyunsun Moon3467a262016-01-14 16:56:26 -0800931
Hyunsun Moonba290072015-12-16 20:53:23 -0800932 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
933 .transition(TABLE_ACCESS_TYPE)
934 .build();
935
936
937 FlowRule flowRule = DefaultFlowRule.builder()
938 .fromApp(appId)
939 .withSelector(selector)
940 .withTreatment(treatment)
941 .withPriority(DEFAULT_PRIORITY)
942 .forDevice(deviceId)
943 .forTable(TABLE_IN_PORT)
944 .makePermanent()
945 .build();
946
947 processFlowRule(true, flowRule);
948
949 selector = DefaultTrafficSelector.builder()
950 .matchInPort(inPort)
951 .build();
Hyunsun Moon3467a262016-01-14 16:56:26 -0800952
Hyunsun Moonba290072015-12-16 20:53:23 -0800953 treatment = DefaultTrafficTreatment.builder()
954 .transition(TABLE_IN_SERVICE)
955 .build();
956
957 flowRule = DefaultFlowRule.builder()
958 .fromApp(appId)
959 .withSelector(selector)
960 .withTreatment(treatment)
Hyunsun Moon64ec6142016-01-29 18:57:05 -0800961 .withPriority(LOW_PRIORITY)
Hyunsun Moonba290072015-12-16 20:53:23 -0800962 .forDevice(deviceId)
963 .forTable(TABLE_IN_PORT)
964 .makePermanent()
965 .build();
966
967 processFlowRule(true, flowRule);
968 }
969
970 /**
971 * Populates direct VM access rules for ACCESS_TYPE table.
972 * These rules are installed to all devices.
973 *
974 * @param srcRange source ip range
975 * @param dstRange destination ip range
976 */
977 private void populateDirectAccessRule(Ip4Prefix srcRange, Ip4Prefix dstRange) {
978 TrafficSelector selector = DefaultTrafficSelector.builder()
979 .matchEthType(Ethernet.TYPE_IPV4)
980 .matchIPSrc(srcRange)
981 .matchIPDst(dstRange)
982 .build();
Hyunsun Moon3467a262016-01-14 16:56:26 -0800983
Hyunsun Moonba290072015-12-16 20:53:23 -0800984 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
985 .transition(TABLE_DST_IP)
986 .build();
987
988 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
989 FlowRule flowRuleDirect = DefaultFlowRule.builder()
990 .fromApp(appId)
991 .withSelector(selector)
992 .withTreatment(treatment)
Hyunsun Moon1257efc2016-02-01 23:00:56 -0800993 .withPriority(DEFAULT_PRIORITY)
994 .forDevice(device.id())
995 .forTable(TABLE_ACCESS_TYPE)
996 .makePermanent()
997 .build();
998
999 processFlowRule(true, flowRuleDirect);
1000 }
1001 }
1002
1003 /**
1004 * Populates drop rules that does not match any direct access rules but has
1005 * destination to a different service network in ACCESS_TYPE table.
1006 *
1007 * @param dstRange destination ip range
1008 */
1009 private void populateServiceIsolationRule(Ip4Prefix dstRange) {
1010 TrafficSelector selector = DefaultTrafficSelector.builder()
1011 .matchEthType(Ethernet.TYPE_IPV4)
1012 .matchIPDst(dstRange)
1013 .build();
1014
1015 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
1016 .drop()
1017 .build();
1018
1019 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
1020 FlowRule flowRuleDirect = DefaultFlowRule.builder()
1021 .fromApp(appId)
1022 .withSelector(selector)
1023 .withTreatment(treatment)
Hyunsun Moon64ec6142016-01-29 18:57:05 -08001024 .withPriority(LOW_PRIORITY)
Hyunsun Moonba290072015-12-16 20:53:23 -08001025 .forDevice(device.id())
1026 .forTable(TABLE_ACCESS_TYPE)
1027 .makePermanent()
1028 .build();
1029
1030 processFlowRule(true, flowRuleDirect);
1031 }
1032 }
1033
1034 /**
1035 * Populates indirect service access rules for ACCESS_TYPE table.
1036 * These rules are installed to all devices.
1037 *
1038 * @param srcRange source range
1039 * @param serviceIp service ip
1040 * @param outGroups list of output group
1041 */
1042 private void populateIndirectAccessRule(Ip4Prefix srcRange, Ip4Address serviceIp,
1043 Map<DeviceId, GroupId> outGroups) {
1044 TrafficSelector selector = DefaultTrafficSelector.builder()
1045 .matchEthType(Ethernet.TYPE_IPV4)
1046 .matchIPSrc(srcRange)
1047 .matchIPDst(serviceIp.toIpPrefix())
1048 .build();
1049
1050 for (Map.Entry<DeviceId, GroupId> outGroup : outGroups.entrySet()) {
1051 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
1052 .group(outGroup.getValue())
1053 .build();
1054
1055 FlowRule flowRule = DefaultFlowRule.builder()
1056 .fromApp(appId)
1057 .withSelector(selector)
1058 .withTreatment(treatment)
Hyunsun Moon1257efc2016-02-01 23:00:56 -08001059 .withPriority(HIGH_PRIORITY)
Hyunsun Moonba290072015-12-16 20:53:23 -08001060 .forDevice(outGroup.getKey())
1061 .forTable(TABLE_ACCESS_TYPE)
1062 .makePermanent()
1063 .build();
1064
1065 processFlowRule(true, flowRule);
1066 }
1067 }
1068
1069 /**
1070 * Populates flow rules for IN_SERVICE table.
1071 *
1072 * @param inPorts list of inports related to the service for each device
1073 * @param outGroups set of output groups
1074 */
1075 private void populateInServiceRule(Map<DeviceId, Set<PortNumber>> inPorts, Map<DeviceId, GroupId> outGroups) {
1076 checkNotNull(inPorts);
1077 checkNotNull(outGroups);
1078
1079 for (Map.Entry<DeviceId, Set<PortNumber>> entry : inPorts.entrySet()) {
1080 Set<PortNumber> ports = entry.getValue();
1081 DeviceId deviceId = entry.getKey();
1082
1083 GroupId groupId = outGroups.get(deviceId);
1084 if (groupId == null) {
1085 continue;
1086 }
1087
1088 ports.stream().forEach(port -> {
1089 TrafficSelector selector = DefaultTrafficSelector.builder()
1090 .matchInPort(port)
1091 .build();
Hyunsun Moon3467a262016-01-14 16:56:26 -08001092
Hyunsun Moonba290072015-12-16 20:53:23 -08001093 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
1094 .group(groupId)
1095 .build();
1096
1097 FlowRule flowRule = DefaultFlowRule.builder()
1098 .fromApp(appId)
1099 .withSelector(selector)
1100 .withTreatment(treatment)
1101 .withPriority(DEFAULT_PRIORITY)
1102 .forDevice(deviceId)
1103 .forTable(TABLE_IN_SERVICE)
1104 .makePermanent()
1105 .build();
1106
1107 processFlowRule(true, flowRule);
1108 });
1109 }
1110 }
1111
1112 /**
1113 * Populates flow rules for DST_IP table.
1114 *
1115 * @param deviceId device id
1116 * @param inPort in port
1117 * @param dstMac mac address
1118 * @param dstIp destination ip
1119 * @param tunnelId tunnel id
1120 * @param tunnelIp tunnel remote ip
1121 */
1122 private void populateDstIpRule(DeviceId deviceId, PortNumber inPort, MacAddress dstMac,
1123 IpAddress dstIp, long tunnelId, IpAddress tunnelIp) {
1124 TrafficSelector selector = DefaultTrafficSelector.builder()
1125 .matchEthType(Ethernet.TYPE_IPV4)
1126 .matchIPDst(dstIp.toIpPrefix())
1127 .build();
Hyunsun Moon3467a262016-01-14 16:56:26 -08001128
Hyunsun Moonba290072015-12-16 20:53:23 -08001129 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
1130 .setEthDst(dstMac)
1131 .setOutput(inPort)
1132 .build();
1133
1134 FlowRule flowRule = DefaultFlowRule.builder()
1135 .fromApp(appId)
1136 .withSelector(selector)
1137 .withTreatment(treatment)
1138 .withPriority(DEFAULT_PRIORITY)
1139 .forDevice(deviceId)
1140 .forTable(TABLE_DST_IP)
1141 .makePermanent()
1142 .build();
1143
1144 processFlowRule(true, flowRule);
1145
1146 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
1147 if (device.id().equals(deviceId)) {
1148 continue;
1149 }
1150
1151 ExtensionTreatment tunnelDst = getTunnelDst(device.id(), tunnelIp.getIp4Address());
1152 if (tunnelDst == null) {
1153 continue;
1154 }
1155
1156 treatment = DefaultTrafficTreatment.builder()
1157 .setEthDst(dstMac)
1158 .setTunnelId(tunnelId)
1159 .extension(tunnelDst, device.id())
1160 .setOutput(getTunnelPort(device.id()))
1161 .build();
1162
1163 flowRule = DefaultFlowRule.builder()
1164 .fromApp(appId)
1165 .withSelector(selector)
1166 .withTreatment(treatment)
1167 .withPriority(DEFAULT_PRIORITY)
1168 .forDevice(device.id())
1169 .forTable(TABLE_DST_IP)
1170 .makePermanent()
1171 .build();
1172
1173 processFlowRule(true, flowRule);
1174 }
1175 }
1176
1177 /**
1178 * Populates flow rules for TUNNEL_ID table.
1179 *
1180 * @param deviceId device id
1181 * @param inPort in port
1182 * @param mac mac address
1183 * @param tunnelId tunnel id
1184 */
1185 private void populateTunnelInRule(DeviceId deviceId, PortNumber inPort, MacAddress mac, long tunnelId) {
1186 TrafficSelector selector = DefaultTrafficSelector.builder()
1187 .matchTunnelId(tunnelId)
1188 .matchEthDst(mac)
1189 .build();
1190
1191 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
1192 .setOutput(inPort)
1193 .build();
1194
1195 FlowRule flowRule = DefaultFlowRule.builder()
1196 .fromApp(appId)
1197 .withSelector(selector)
1198 .withTreatment(treatment)
1199 .withPriority(DEFAULT_PRIORITY)
1200 .forDevice(deviceId)
1201 .forTable(TABLE_TUNNEL_IN)
1202 .makePermanent()
1203 .build();
1204
1205 processFlowRule(true, flowRule);
1206 }
1207
1208 /**
1209 * Installs or uninstall a given rule.
1210 *
1211 * @param install true to install, false to uninstall
1212 * @param rule rule
1213 */
1214 private void processFlowRule(boolean install, FlowRule rule) {
1215 FlowRuleOperations.Builder oBuilder = FlowRuleOperations.builder();
1216 oBuilder = install ? oBuilder.add(rule) : oBuilder.remove(rule);
1217
1218 flowRuleService.apply(oBuilder.build(new FlowRuleOperationsContext() {
1219 @Override
1220 public void onError(FlowRuleOperations ops) {
1221 log.error(String.format("Failed %s, %s", ops.toString(), rule.toString()));
1222 }
1223 }));
1224 }
1225
1226 /**
1227 * Returns tunnel port of the device.
1228 *
1229 * @param deviceId device id
1230 * @return tunnel port number, or null if no tunnel port exists on a given device
1231 */
1232 private PortNumber getTunnelPort(DeviceId deviceId) {
Hyunsun Moon2bf68e72016-01-15 11:41:14 -08001233 Port port = deviceService.getPorts(deviceId).stream()
Hyunsun Moon01556a52016-02-12 12:48:47 -08001234 .filter(p -> p.annotations().value(PORT_NAME).contains(tunnelType))
1235 .findFirst().orElse(null);
Hyunsun Moon2bf68e72016-01-15 11:41:14 -08001236
1237 return port == null ? null : port.number();
Hyunsun Moonba290072015-12-16 20:53:23 -08001238 }
1239
1240 /**
Hyunsun Moon126171d2016-02-09 01:55:48 -08001241 * Returns data plane interface port name of a given device.
Hyunsun Moon3467a262016-01-14 16:56:26 -08001242 *
1243 * @param deviceId device id
Hyunsun Moon126171d2016-02-09 01:55:48 -08001244 * @param dpIntf data plane interface port name
1245 * @return data plane interface port number, or null if no such port exists
Hyunsun Moon3467a262016-01-14 16:56:26 -08001246 */
Hyunsun Moon126171d2016-02-09 01:55:48 -08001247 private PortNumber getDpPort(DeviceId deviceId, String dpIntf) {
Hyunsun Moon2bf68e72016-01-15 11:41:14 -08001248 Port port = deviceService.getPorts(deviceId).stream()
Hyunsun Moon01556a52016-02-12 12:48:47 -08001249 .filter(p -> p.annotations().value(PORT_NAME).contains(dpIntf) &&
1250 p.isEnabled())
1251 .findFirst().orElse(null);
Hyunsun Moon2bf68e72016-01-15 11:41:14 -08001252
1253 return port == null ? null : port.number();
Hyunsun Moon3467a262016-01-14 16:56:26 -08001254 }
1255
Hyunsun Moon01556a52016-02-12 12:48:47 -08001256 /** Returns data plane interface port number of a given host.
1257 *
1258 * @param host host
1259 * @return port number, or null
1260 */
1261 private PortNumber getDpPort(Host host) {
1262 String portName = host.annotations().value(DATA_PLANE_INTF);
1263 return portName == null ? null : getDpPort(host.location().deviceId(), portName);
1264 }
1265
1266 /**
1267 * Returns service vlan from a given host.
1268 *
1269 * @param host host
1270 * @return vlan id, or null
1271 */
1272 private VlanId getServiceVlan(Host host) {
1273 String serviceVlan = host.annotations().value(S_TAG);
1274 return serviceVlan == null ? null : VlanId.vlanId(Short.parseShort(serviceVlan));
1275 }
1276
Hyunsun Moon3467a262016-01-14 16:56:26 -08001277 /**
Hyunsun Moonba290072015-12-16 20:53:23 -08001278 * Returns the inport from a given flow rule if the rule contains the match of it.
1279 *
1280 * @param flowRule flow rule
1281 * @return port number, or null if the rule doesn't have inport match
1282 */
1283 private PortNumber getInPort(FlowRule flowRule) {
1284 Criterion criterion = flowRule.selector().getCriterion(IN_PORT);
1285 if (criterion != null && criterion instanceof PortCriterion) {
1286 PortCriterion port = (PortCriterion) criterion;
1287 return port.port();
1288 } else {
1289 return null;
1290 }
1291 }
1292
1293 /**
1294 * Returns the destination mac address from a given flow rule if the rule
1295 * contains the instruction of it.
1296 *
1297 * @param flowRule flow rule
1298 * @return mac address, or null if the rule doesn't have destination mac instruction
1299 */
1300 private MacAddress getDstMacFromTreatment(FlowRule flowRule) {
1301 Instruction instruction = flowRule.treatment().allInstructions().stream()
1302 .filter(inst -> inst instanceof ModEtherInstruction &&
1303 ((ModEtherInstruction) inst).subtype().equals(ETH_DST))
1304 .findFirst()
1305 .orElse(null);
1306
1307 if (instruction == null) {
Hyunsun Moon05f528a2015-11-04 17:34:35 -08001308 return null;
1309 }
1310
Hyunsun Moonba290072015-12-16 20:53:23 -08001311 return ((ModEtherInstruction) instruction).mac();
Hyunsun Moon05f528a2015-11-04 17:34:35 -08001312 }
1313
1314 /**
Hyunsun Moonba290072015-12-16 20:53:23 -08001315 * Returns the destination mac address from a given flow rule if the rule
1316 * contains the match of it.
Hyunsun Moon05f528a2015-11-04 17:34:35 -08001317 *
Hyunsun Moonba290072015-12-16 20:53:23 -08001318 * @param flowRule flow rule
1319 * @return mac address, or null if the rule doesn't have destination mac match
Hyunsun Moon05f528a2015-11-04 17:34:35 -08001320 */
Hyunsun Moonba290072015-12-16 20:53:23 -08001321 private MacAddress getDstMacFromSelector(FlowRule flowRule) {
1322 Criterion criterion = flowRule.selector().getCriterion(Criterion.Type.ETH_DST);
1323 if (criterion != null && criterion instanceof EthCriterion) {
1324 EthCriterion eth = (EthCriterion) criterion;
1325 return eth.mac();
1326 } else {
1327 return null;
1328 }
1329 }
1330
1331 /**
1332 * Returns the destination IP from a given flow rule if the rule contains
1333 * the match of it.
1334 *
1335 * @param flowRule flow rule
1336 * @return ip prefix, or null if the rule doesn't have ip match
1337 */
1338 private IpPrefix getDstIpFromSelector(FlowRule flowRule) {
1339 Criterion criterion = flowRule.selector().getCriterion(IPV4_DST);
1340 if (criterion != null && criterion instanceof IPCriterion) {
1341 IPCriterion ip = (IPCriterion) criterion;
1342 return ip.ip();
1343 } else {
1344 return null;
1345 }
1346 }
1347
1348 /**
1349 * Returns the source IP from a given flow rule if the rule contains
1350 * the match of it.
1351 *
1352 * @param flowRule flow rule
1353 * @return ip prefix, or null if the rule doesn't have ip match
1354 */
1355 private IpPrefix getSrcIpFromSelector(FlowRule flowRule) {
1356 Criterion criterion = flowRule.selector().getCriterion(IPV4_SRC);
1357 if (criterion != null && criterion instanceof IPCriterion) {
1358 IPCriterion ip = (IPCriterion) criterion;
1359 return ip.ip();
1360 } else {
1361 return null;
1362 }
1363 }
1364
1365 /**
1366 * Returns the group ID from a given flow rule if the rule contains the
1367 * treatment of it.
1368 *
1369 * @param flowRule flow rule
1370 * @return group id, or null if the rule doesn't have group instruction
1371 */
1372 private GroupId getGroupIdFromTreatment(FlowRule flowRule) {
1373 Instruction instruction = flowRule.treatment().allInstructions().stream()
1374 .filter(inst -> inst instanceof Instructions.GroupInstruction)
1375 .findFirst()
1376 .orElse(null);
1377
1378 if (instruction == null) {
1379 return null;
1380 }
1381
1382 return ((Instructions.GroupInstruction) instruction).groupId();
Hyunsun Moon05f528a2015-11-04 17:34:35 -08001383 }
1384
1385 /**
Hyunsun Moon64ec6142016-01-29 18:57:05 -08001386 * Returns the output port number from a given flow rule.
1387 *
1388 * @param flowRule flow rule
1389 * @return port number, or null if the rule does not have output instruction
1390 */
1391 private PortNumber getOutputFromTreatment(FlowRule flowRule) {
1392 Instruction instruction = flowRule.treatment().allInstructions().stream()
Hyunsun Moon01556a52016-02-12 12:48:47 -08001393 .filter(inst -> inst instanceof Instructions.OutputInstruction)
Hyunsun Moon64ec6142016-01-29 18:57:05 -08001394 .findFirst()
1395 .orElse(null);
1396
1397 if (instruction == null) {
1398 return null;
1399 }
1400
1401 return ((Instructions.OutputInstruction) instruction).port();
1402 }
1403
1404 /**
Hyunsun Moon01556a52016-02-12 12:48:47 -08001405 * Returns if a given flow rule has vlan push instruction or not.
1406 *
1407 * @param flowRule flow rule
1408 * @return true if it includes vlan push, or false
1409 */
1410 private boolean isVlanPushFromTreatment(FlowRule flowRule) {
1411 Instruction instruction = flowRule.treatment().allInstructions().stream()
1412 .filter(inst -> inst instanceof L2ModificationInstruction)
1413 .filter(inst -> ((L2ModificationInstruction) inst).subtype().equals(VLAN_PUSH))
1414 .findAny()
1415 .orElse(null);
1416
1417 return instruction != null;
1418 }
1419
1420 /**
Hyunsun Moon3467a262016-01-14 16:56:26 -08001421 * Creates a new group for a given service.
1422 *
1423 * @param deviceId device id to create a group
1424 * @param service cord service
1425 * @return group id, or null if it fails to create
1426 */
1427 private GroupId createServiceGroup(DeviceId deviceId, CordService service) {
1428 checkNotNull(service);
1429
1430 GroupKey groupKey = getGroupKey(service.id());
1431 Group group = groupService.getGroup(deviceId, groupKey);
1432 GroupId groupId = getGroupId(service.id(), deviceId);
1433
1434 if (group != null) {
1435 log.debug("Group {} is already exist in {}", service.id(), deviceId);
1436 return groupId;
1437 }
1438
1439 GroupBuckets buckets = getServiceGroupBuckets(deviceId, service.segmentationId(), service.hosts());
1440 GroupDescription groupDescription = new DefaultGroupDescription(
1441 deviceId,
1442 GroupDescription.Type.SELECT,
1443 buckets,
1444 groupKey,
1445 groupId.id(),
1446 appId);
1447
1448 groupService.addGroup(groupDescription);
1449
1450 return groupId;
1451 }
1452
1453 /**
1454 * Returns group buckets for a given device.
1455 *
1456 * @param deviceId device id
1457 * @param tunnelId tunnel id
1458 * @param hosts list of host
1459 * @return group buckets
1460 */
1461 private GroupBuckets getServiceGroupBuckets(DeviceId deviceId, long tunnelId, Map<Host, IpAddress> hosts) {
1462 List<GroupBucket> buckets = Lists.newArrayList();
1463
1464 for (Map.Entry<Host, IpAddress> entry : hosts.entrySet()) {
1465 Host host = entry.getKey();
1466 Ip4Address remoteIp = entry.getValue().getIp4Address();
1467 DeviceId hostDevice = host.location().deviceId();
1468
1469 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
1470 .builder()
1471 .setEthDst(host.mac());
1472
1473 if (deviceId.equals(hostDevice)) {
1474 tBuilder.setOutput(host.location().port());
1475 } else {
1476 ExtensionTreatment tunnelDst = getTunnelDst(deviceId, remoteIp);
1477 if (tunnelDst == null) {
1478 continue;
1479 }
1480
1481 tBuilder.extension(tunnelDst, deviceId)
1482 .setTunnelId(tunnelId)
1483 .setOutput(getTunnelPort(hostDevice));
1484 }
1485
1486 buckets.add(DefaultGroupBucket.createSelectGroupBucket(tBuilder.build()));
1487 }
1488
1489 return new GroupBuckets(buckets);
1490 }
1491
1492 /**
1493 * Returns globally unique group ID.
1494 *
1495 * @param serviceId service id
1496 * @param deviceId device id
1497 * @return group id
1498 */
1499 private GroupId getGroupId(CordServiceId serviceId, DeviceId deviceId) {
1500 return new DefaultGroupId(Objects.hash(serviceId, deviceId));
1501 }
1502
1503 /**
1504 * Returns group key of a service.
1505 *
1506 * @param serviceId service id
1507 * @return group key
1508 */
1509 private GroupKey getGroupKey(CordServiceId serviceId) {
1510 return new DefaultGroupKey(serviceId.id().getBytes());
1511 }
1512
1513 /**
Hyunsun Moon05f528a2015-11-04 17:34:35 -08001514 * Returns extension instruction to set tunnel destination.
1515 *
1516 * @param deviceId device id
1517 * @param remoteIp tunnel destination address
1518 * @return extension treatment or null if it fails to get instruction
1519 */
Hyunsun Moonba290072015-12-16 20:53:23 -08001520 private ExtensionTreatment getTunnelDst(DeviceId deviceId, Ip4Address remoteIp) {
Hyunsun Moon05f528a2015-11-04 17:34:35 -08001521 try {
1522 Driver driver = driverService.getDriver(deviceId);
Hyunsun Moonba290072015-12-16 20:53:23 -08001523 DefaultDriverData driverData = new DefaultDriverData(driver, deviceId);
1524 DriverHandler handler = new DefaultDriverHandler(driverData);
1525 ExtensionTreatmentResolver resolver = handler.behaviour(ExtensionTreatmentResolver.class);
Hyunsun Moon05f528a2015-11-04 17:34:35 -08001526
Hyunsun Moonba290072015-12-16 20:53:23 -08001527 ExtensionTreatment treatment =
1528 resolver.getExtensionInstruction(NICIRA_SET_TUNNEL_DST.type());
Hyunsun Moon05f528a2015-11-04 17:34:35 -08001529 treatment.setPropertyValue("tunnelDst", remoteIp);
1530
1531 return treatment;
Hyunsun Moonba290072015-12-16 20:53:23 -08001532 } catch (ItemNotFoundException | UnsupportedOperationException |
1533 ExtensionPropertyException e) {
1534 log.error("Failed to get extension instruction {}", deviceId);
Hyunsun Moon05f528a2015-11-04 17:34:35 -08001535 return null;
1536 }
1537 }
1538}
Hyunsun Moonba290072015-12-16 20:53:23 -08001539