blob: f3877e095f21b1a0ccb981c0fbbc5c1d8f5253c5 [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;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080033import org.onosproject.net.Device;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080034import org.onosproject.net.DeviceId;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080035import org.onosproject.net.Host;
Hyunsun Moon5a4346f2016-01-15 11:41:14 -080036import org.onosproject.net.Port;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080037import org.onosproject.net.PortNumber;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080038import org.onosproject.net.behaviour.ExtensionTreatmentResolver;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080039import org.onosproject.net.device.DeviceService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080040import org.onosproject.net.driver.DefaultDriverData;
41import org.onosproject.net.driver.DefaultDriverHandler;
42import org.onosproject.net.driver.Driver;
43import org.onosproject.net.driver.DriverHandler;
44import org.onosproject.net.driver.DriverService;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080045import org.onosproject.net.flow.DefaultFlowRule;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080046import org.onosproject.net.flow.DefaultTrafficSelector;
47import org.onosproject.net.flow.DefaultTrafficTreatment;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080048import org.onosproject.net.flow.FlowRule;
49import org.onosproject.net.flow.FlowRuleOperations;
50import org.onosproject.net.flow.FlowRuleOperationsContext;
51import org.onosproject.net.flow.FlowRuleService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080052import org.onosproject.net.flow.TrafficSelector;
53import org.onosproject.net.flow.TrafficTreatment;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080054import org.onosproject.net.flow.criteria.Criterion;
55import org.onosproject.net.flow.criteria.EthCriterion;
56import org.onosproject.net.flow.criteria.IPCriterion;
57import org.onosproject.net.flow.criteria.PortCriterion;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080058import org.onosproject.net.flow.instructions.ExtensionPropertyException;
59import org.onosproject.net.flow.instructions.ExtensionTreatment;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080060import org.onosproject.net.flow.instructions.Instruction;
61import org.onosproject.net.flow.instructions.Instructions;
Hyunsun Moon6d247342016-02-12 12:48:47 -080062import org.onosproject.net.flow.instructions.L2ModificationInstruction;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080063import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
64import org.onosproject.net.group.DefaultGroupBucket;
65import org.onosproject.net.group.DefaultGroupDescription;
66import org.onosproject.net.group.DefaultGroupKey;
67import org.onosproject.net.group.Group;
68import org.onosproject.net.group.GroupBucket;
69import org.onosproject.net.group.GroupBuckets;
70import org.onosproject.net.group.GroupDescription;
71import org.onosproject.net.group.GroupKey;
72import org.onosproject.net.group.GroupService;
sangho93447f12016-02-24 00:33:22 +090073import org.onosproject.openstackinterface.OpenstackNetwork;
74import org.onosproject.openstackinterface.OpenstackSubnet;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080075import org.slf4j.Logger;
76
Hyunsun Moon4161e6f2016-01-07 01:32:31 -080077import java.util.ArrayList;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080078import java.util.List;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080079import java.util.Map;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080080import java.util.Objects;
81import java.util.Set;
82import java.util.stream.Collectors;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080083
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080084import static com.google.common.base.Preconditions.checkNotNull;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080085import static org.onosproject.net.Device.Type.SWITCH;
86import static org.onosproject.net.flow.criteria.Criterion.Type.IN_PORT;
87import static org.onosproject.net.flow.criteria.Criterion.Type.IPV4_DST;
88import static org.onosproject.net.flow.criteria.Criterion.Type.IPV4_SRC;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080089import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080090import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.ETH_DST;
Hyunsun Moon6d247342016-02-12 12:48:47 -080091import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.VLAN_PUSH;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080092import static org.slf4j.LoggerFactory.getLogger;
93
94/**
Hyunsun Moonc71231d2015-12-16 20:53:23 -080095 * Populates rules for CORD VTN service.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080096 */
Hyunsun Moonc71231d2015-12-16 20:53:23 -080097public class CordVtnRuleInstaller {
98
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080099 protected final Logger log = getLogger(getClass());
100
Hyunsun Moon4a915152016-01-14 16:56:26 -0800101 private static final int TABLE_FIRST = 0;
102 private static final int TABLE_IN_PORT = 1;
103 private static final int TABLE_ACCESS_TYPE = 2;
104 private static final int TABLE_IN_SERVICE = 3;
105 private static final int TABLE_DST_IP = 4;
106 private static final int TABLE_TUNNEL_IN = 5;
Hyunsun Moon6d247342016-02-12 12:48:47 -0800107 private static final int TABLE_Q_IN_Q = 6;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800108
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800109 private static final int MANAGEMENT_PRIORITY = 55000;
Hyunsun Moon6d247342016-02-12 12:48:47 -0800110 private static final int VSG_PRIORITY = 55000;
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800111 private static final int HIGH_PRIORITY = 50000;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800112 private static final int DEFAULT_PRIORITY = 5000;
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800113 private static final int LOW_PRIORITY = 4000;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800114 private static final int LOWEST_PRIORITY = 0;
Hyunsun Moon4a915152016-01-14 16:56:26 -0800115
116 private static final int VXLAN_UDP_PORT = 4789;
Hyunsun Moon6d247342016-02-12 12:48:47 -0800117 private static final VlanId VLAN_WAN = VlanId.vlanId((short) 500);
118
119 private static final String PORT_NAME = "portName";
120 private static final String DATA_PLANE_INTF = "dataPlaneIntf";
121 private static final String S_TAG = "stag";
Hyunsun Moon98025542016-03-08 04:36:02 -0800122 private static final String OVS_HW_VERSION = "Open vSwitch";
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;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800129 private final String tunnelType;
130
131 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800132 * Creates a new rule populator.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800133 *
134 * @param appId application id
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800135 * @param flowRuleService flow rule service
136 * @param deviceService device service
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800137 * @param driverService driver service
Jian Lidfba7392016-01-22 16:46:58 -0800138 * @param groupService group service
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800139 * @param tunnelType tunnel type
140 */
141 public CordVtnRuleInstaller(ApplicationId appId,
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800142 FlowRuleService flowRuleService,
143 DeviceService deviceService,
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800144 DriverService driverService,
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800145 GroupService groupService,
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800146 String tunnelType) {
147 this.appId = appId;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800148 this.flowRuleService = flowRuleService;
149 this.deviceService = deviceService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800150 this.driverService = driverService;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800151 this.groupService = groupService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800152 this.tunnelType = checkNotNull(tunnelType);
153 }
154
155 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800156 * Installs table miss rule to a give device.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800157 *
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800158 * @param deviceId device id to install the rules
Hyunsun Moon133fd792016-02-09 01:55:48 -0800159 * @param dpIntf data plane interface name
160 * @param dpIp data plane ip address
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800161 */
Hyunsun Moon133fd792016-02-09 01:55:48 -0800162 public void init(DeviceId deviceId, String dpIntf, IpAddress dpIp) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800163 // default is drop packets which can be accomplished without
164 // a table miss entry for all table.
Hyunsun Moon4a915152016-01-14 16:56:26 -0800165 PortNumber tunnelPort = getTunnelPort(deviceId);
Hyunsun Moon133fd792016-02-09 01:55:48 -0800166 PortNumber dpPort = getDpPort(deviceId, dpIntf);
Hyunsun Moon4a915152016-01-14 16:56:26 -0800167
Hyunsun Moon133fd792016-02-09 01:55:48 -0800168 processFirstTable(deviceId, dpPort, dpIp);
169 processInPortTable(deviceId, tunnelPort, dpPort);
170 processAccessTypeTable(deviceId, dpPort);
Hyunsun Moon6d247342016-02-12 12:48:47 -0800171 processQInQTable(deviceId, dpPort);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800172 }
173
174 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800175 * Populates basic rules that connect a VM to the other VMs in the system.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800176 *
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800177 * @param host host
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800178 * @param tunnelIp tunnel ip
179 * @param vNet openstack network
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800180 */
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800181 public void populateBasicConnectionRules(Host host, IpAddress tunnelIp, OpenstackNetwork vNet) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800182 checkNotNull(host);
183 checkNotNull(vNet);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800184
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800185 DeviceId deviceId = host.location().deviceId();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800186 PortNumber inPort = host.location().port();
187 MacAddress dstMac = host.mac();
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800188 IpAddress hostIp = host.ipAddresses().stream().findFirst().get();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800189 long tunnelId = Long.parseLong(vNet.segmentId());
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800190
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800191 OpenstackSubnet subnet = vNet.subnets().stream()
192 .findFirst()
193 .orElse(null);
194
195 if (subnet == null) {
196 log.error("Failed to get subnet for {}", host.id());
197 return;
198 }
199
200 populateLocalInPortRule(deviceId, inPort, hostIp);
201 populateDirectAccessRule(Ip4Prefix.valueOf(subnet.cidr()), Ip4Prefix.valueOf(subnet.cidr()));
Hyunsun Moon81ab23b2016-02-01 23:00:56 -0800202 populateServiceIsolationRule(Ip4Prefix.valueOf(subnet.cidr()));
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800203 populateDstIpRule(deviceId, inPort, dstMac, hostIp, tunnelId, tunnelIp);
204 populateTunnelInRule(deviceId, inPort, dstMac, tunnelId);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800205 }
206
207 /**
Hyunsun Moond5f6c3b2016-02-18 15:37:22 -0800208 * Removes all rules related to a given service VM host.
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800209 *
210 * @param host host to be removed
211 */
212 public void removeBasicConnectionRules(Host host) {
213 checkNotNull(host);
214
215 DeviceId deviceId = host.location().deviceId();
216 MacAddress mac = host.mac();
217 PortNumber port = host.location().port();
218 IpAddress ip = host.ipAddresses().stream().findFirst().orElse(null);
219
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800220 for (FlowRule flowRule : flowRuleService.getFlowRulesById(appId)) {
221 if (flowRule.deviceId().equals(deviceId)) {
222 PortNumber inPort = getInPort(flowRule);
223 if (inPort != null && inPort.equals(port)) {
224 processFlowRule(false, flowRule);
225 continue;
226 }
Hyunsun Moond5f6c3b2016-02-18 15:37:22 -0800227
228 PortNumber output = getOutputFromTreatment(flowRule);
229 if (output != null && output.equals(host.location().port())) {
230 processFlowRule(false, flowRule);
231 }
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800232 }
233
234 MacAddress dstMac = getDstMacFromTreatment(flowRule);
235 if (dstMac != null && dstMac.equals(mac)) {
236 processFlowRule(false, flowRule);
237 continue;
238 }
239
240 dstMac = getDstMacFromSelector(flowRule);
241 if (dstMac != null && dstMac.equals(mac)) {
242 processFlowRule(false, flowRule);
243 continue;
244 }
245
246 IpPrefix dstIp = getDstIpFromSelector(flowRule);
247 if (dstIp != null && dstIp.equals(ip.toIpPrefix())) {
248 processFlowRule(false, flowRule);
249 }
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800250 }
251
252 // TODO uninstall same network access rule in access table if no vm exists in the network
253 }
254
255 /**
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800256 * Populates service dependency rules.
257 *
258 * @param tService tenant cord service
259 * @param pService provider cord service
Hyunsun Moon640f183e2016-02-10 17:02:37 -0800260 * @param isBidirectional true to enable bidirectional connection between two services
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800261 */
Hyunsun Moon640f183e2016-02-10 17:02:37 -0800262 public void populateServiceDependencyRules(CordService tService, CordService pService,
263 boolean isBidirectional) {
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800264 checkNotNull(tService);
265 checkNotNull(pService);
266
267 Ip4Prefix srcRange = tService.serviceIpRange().getIp4Prefix();
268 Ip4Prefix dstRange = pService.serviceIpRange().getIp4Prefix();
269 Ip4Address serviceIp = pService.serviceIp().getIp4Address();
270
271 Map<DeviceId, GroupId> outGroups = Maps.newHashMap();
272 Map<DeviceId, Set<PortNumber>> inPorts = Maps.newHashMap();
273
274 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
Hyunsun Moon98025542016-03-08 04:36:02 -0800275 if (!device.hwVersion().equals(OVS_HW_VERSION)) {
276 continue;
277 }
278
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800279 GroupId groupId = createServiceGroup(device.id(), pService);
280 outGroups.put(device.id(), groupId);
281
282 Set<PortNumber> vms = tService.hosts().keySet()
283 .stream()
284 .filter(host -> host.location().deviceId().equals(device.id()))
285 .map(host -> host.location().port())
286 .collect(Collectors.toSet());
287 inPorts.put(device.id(), vms);
288 }
289
290 populateIndirectAccessRule(srcRange, serviceIp, outGroups);
291 populateDirectAccessRule(srcRange, dstRange);
Hyunsun Moon640f183e2016-02-10 17:02:37 -0800292 if (isBidirectional) {
293 populateDirectAccessRule(dstRange, srcRange);
294 }
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800295 populateInServiceRule(inPorts, outGroups);
296 }
297
298 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800299 * Removes service dependency rules.
300 *
301 * @param tService tenant cord service
302 * @param pService provider cord service
303 */
304 public void removeServiceDependencyRules(CordService tService, CordService pService) {
305 checkNotNull(tService);
306 checkNotNull(pService);
307
308 Ip4Prefix srcRange = tService.serviceIpRange().getIp4Prefix();
309 Ip4Prefix dstRange = pService.serviceIpRange().getIp4Prefix();
310 IpPrefix serviceIp = pService.serviceIp().toIpPrefix();
311
312 Map<DeviceId, GroupId> outGroups = Maps.newHashMap();
313 GroupKey groupKey = new DefaultGroupKey(pService.id().id().getBytes());
314
Hyunsun Moon98025542016-03-08 04:36:02 -0800315 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
316 if (!device.hwVersion().equals(OVS_HW_VERSION)) {
317 continue;
318 }
319
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800320 Group group = groupService.getGroup(device.id(), groupKey);
321 if (group != null) {
322 outGroups.put(device.id(), group.id());
323 }
Hyunsun Moon98025542016-03-08 04:36:02 -0800324 }
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800325
326 for (FlowRule flowRule : flowRuleService.getFlowRulesById(appId)) {
327 IpPrefix dstIp = getDstIpFromSelector(flowRule);
328 IpPrefix srcIp = getSrcIpFromSelector(flowRule);
329
330 if (dstIp != null && dstIp.equals(serviceIp)) {
331 processFlowRule(false, flowRule);
332 continue;
333 }
334
335 if (dstIp != null && srcIp != null) {
336 if (dstIp.equals(dstRange) && srcIp.equals(srcRange)) {
337 processFlowRule(false, flowRule);
338 continue;
339 }
340
341 if (dstIp.equals(srcRange) && srcIp.equals(dstRange)) {
342 processFlowRule(false, flowRule);
343 continue;
344 }
345 }
346
347 GroupId groupId = getGroupIdFromTreatment(flowRule);
348 if (groupId != null && groupId.equals(outGroups.get(flowRule.deviceId()))) {
349 processFlowRule(false, flowRule);
350 }
351 }
352
353 // TODO remove the group if it is not in use
354 }
355
356 /**
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800357 * Updates group buckets for a given service to all devices.
358 *
359 * @param service cord service
360 */
361 public void updateServiceGroup(CordService service) {
362 checkNotNull(service);
363
364 GroupKey groupKey = getGroupKey(service.id());
365
366 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
Hyunsun Moon98025542016-03-08 04:36:02 -0800367 if (!device.hwVersion().equals(OVS_HW_VERSION)) {
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800368 continue;
369 }
370
Hyunsun Moon98025542016-03-08 04:36:02 -0800371 DeviceId deviceId = device.id();
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800372 Group group = groupService.getGroup(deviceId, groupKey);
373 if (group == null) {
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800374 log.trace("No group exists for service {} in {}, do nothing.", service.id(), deviceId);
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800375 continue;
376 }
377
378 List<GroupBucket> oldBuckets = group.buckets().buckets();
379 List<GroupBucket> newBuckets = getServiceGroupBuckets(
380 deviceId, service.segmentationId(), service.hosts()).buckets();
381
382 if (oldBuckets.equals(newBuckets)) {
383 continue;
384 }
385
386 List<GroupBucket> bucketsToRemove = new ArrayList<>(oldBuckets);
387 bucketsToRemove.removeAll(newBuckets);
388 if (!bucketsToRemove.isEmpty()) {
389 groupService.removeBucketsFromGroup(
390 deviceId,
391 groupKey,
392 new GroupBuckets(bucketsToRemove),
393 groupKey, appId);
394 }
395
396 List<GroupBucket> bucketsToAdd = new ArrayList<>(newBuckets);
397 bucketsToAdd.removeAll(oldBuckets);
398 if (!bucketsToAdd.isEmpty()) {
399 groupService.addBucketsToGroup(
400 deviceId,
401 groupKey,
402 new GroupBuckets(bucketsToAdd),
403 groupKey, appId);
404 }
405 }
406 }
407
408 /**
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800409 * Populates flow rules for management network access.
410 *
411 * @param host host which has management network interface
412 * @param mService management network service
413 */
414 public void populateManagementNetworkRules(Host host, CordService mService) {
415 checkNotNull(mService);
416
417 DeviceId deviceId = host.location().deviceId();
418 IpAddress hostIp = host.ipAddresses().stream().findFirst().get();
419
420 TrafficSelector selector = DefaultTrafficSelector.builder()
421 .matchEthType(Ethernet.TYPE_ARP)
422 .matchArpTpa(mService.serviceIp().getIp4Address())
423 .build();
424
425 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
426 .setOutput(PortNumber.LOCAL)
427 .build();
428
429 FlowRule flowRule = DefaultFlowRule.builder()
430 .fromApp(appId)
431 .withSelector(selector)
432 .withTreatment(treatment)
433 .withPriority(MANAGEMENT_PRIORITY)
434 .forDevice(deviceId)
435 .forTable(TABLE_FIRST)
436 .makePermanent()
437 .build();
438
439 processFlowRule(true, flowRule);
440
441 selector = DefaultTrafficSelector.builder()
442 .matchInPort(PortNumber.LOCAL)
443 .matchEthType(Ethernet.TYPE_ARP)
444 .matchArpTpa(hostIp.getIp4Address())
445 .build();
446
447 treatment = DefaultTrafficTreatment.builder()
448 .setOutput(host.location().port())
449 .build();
450
451 flowRule = DefaultFlowRule.builder()
452 .fromApp(appId)
453 .withSelector(selector)
454 .withTreatment(treatment)
455 .withPriority(MANAGEMENT_PRIORITY)
456 .forDevice(deviceId)
457 .forTable(TABLE_FIRST)
458 .makePermanent()
459 .build();
460
461 processFlowRule(true, flowRule);
462
463 selector = DefaultTrafficSelector.builder()
464 .matchInPort(PortNumber.LOCAL)
465 .matchEthType(Ethernet.TYPE_IPV4)
466 .matchIPDst(mService.serviceIpRange())
467 .build();
468
469 treatment = DefaultTrafficTreatment.builder()
470 .transition(TABLE_DST_IP)
471 .build();
472
473 flowRule = DefaultFlowRule.builder()
474 .fromApp(appId)
475 .withSelector(selector)
476 .withTreatment(treatment)
477 .withPriority(MANAGEMENT_PRIORITY)
478 .forDevice(deviceId)
479 .forTable(TABLE_FIRST)
480 .makePermanent()
481 .build();
482
483 processFlowRule(true, flowRule);
484
485 selector = DefaultTrafficSelector.builder()
486 .matchEthType(Ethernet.TYPE_IPV4)
487 .matchIPDst(mService.serviceIp().toIpPrefix())
488 .build();
489
490 treatment = DefaultTrafficTreatment.builder()
491 .setOutput(PortNumber.LOCAL)
492 .build();
493
494 flowRule = DefaultFlowRule.builder()
495 .fromApp(appId)
496 .withSelector(selector)
497 .withTreatment(treatment)
498 .withPriority(MANAGEMENT_PRIORITY)
499 .forDevice(deviceId)
500 .forTable(TABLE_ACCESS_TYPE)
501 .makePermanent()
502 .build();
503
504 processFlowRule(true, flowRule);
505 }
506
507 /**
508 * Removes management network access rules.
509 *
510 * @param host host to be removed
511 * @param mService service for management network
512 */
513 public void removeManagementNetworkRules(Host host, CordService mService) {
514 checkNotNull(mService);
Hyunsun Moond5f6c3b2016-02-18 15:37:22 -0800515 // TODO remove management network specific rules
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800516 }
517
518 /**
Hyunsun Moon6d247342016-02-12 12:48:47 -0800519 * Populates rules for vSG VM.
520 *
521 * @param vSgHost vSG host
522 * @param vSgIps set of ip addresses of vSGs running inside the vSG VM
523 */
524 public void populateSubscriberGatewayRules(Host vSgHost, Set<IpAddress> vSgIps) {
525 VlanId serviceVlan = getServiceVlan(vSgHost);
526 PortNumber dpPort = getDpPort(vSgHost);
527
528 if (serviceVlan == null || dpPort == null) {
529 log.warn("Failed to populate rules for vSG VM {}", vSgHost.id());
530 return;
531 }
532
533 // for traffics with s-tag, strip the tag and take through the vSG VM
534 TrafficSelector selector = DefaultTrafficSelector.builder()
Hyunsun Moond5f6c3b2016-02-18 15:37:22 -0800535 .matchInPort(dpPort)
Hyunsun Moon6d247342016-02-12 12:48:47 -0800536 .matchVlanId(serviceVlan)
537 .build();
538
539 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Hyunsun Moon6d247342016-02-12 12:48:47 -0800540 .setOutput(vSgHost.location().port())
541 .build();
542
543 FlowRule flowRule = DefaultFlowRule.builder()
544 .fromApp(appId)
545 .withSelector(selector)
546 .withTreatment(treatment)
547 .withPriority(DEFAULT_PRIORITY)
548 .forDevice(vSgHost.location().deviceId())
549 .forTable(TABLE_Q_IN_Q)
550 .makePermanent()
551 .build();
552
553 processFlowRule(true, flowRule);
554
555 // for traffics with customer vlan, tag with the service vlan based on input port with
556 // lower priority to avoid conflict with WAN tag
557 selector = DefaultTrafficSelector.builder()
558 .matchInPort(vSgHost.location().port())
Hyunsun Moond5f6c3b2016-02-18 15:37:22 -0800559 .matchVlanId(serviceVlan)
Hyunsun Moon6d247342016-02-12 12:48:47 -0800560 .build();
561
562 treatment = DefaultTrafficTreatment.builder()
Hyunsun Moon6d247342016-02-12 12:48:47 -0800563 .setOutput(dpPort)
564 .build();
565
566 flowRule = DefaultFlowRule.builder()
567 .fromApp(appId)
568 .withSelector(selector)
569 .withTreatment(treatment)
Hyunsun Moond5f6c3b2016-02-18 15:37:22 -0800570 .withPriority(DEFAULT_PRIORITY)
Hyunsun Moon6d247342016-02-12 12:48:47 -0800571 .forDevice(vSgHost.location().deviceId())
572 .forTable(TABLE_Q_IN_Q)
573 .makePermanent()
574 .build();
575
576 processFlowRule(true, flowRule);
577
578 // for traffic coming from WAN, tag 500 and take through the vSG VM
579 // based on destination ip
580 vSgIps.stream().forEach(ip -> {
581 TrafficSelector downstream = DefaultTrafficSelector.builder()
582 .matchEthType(Ethernet.TYPE_IPV4)
583 .matchIPDst(ip.toIpPrefix())
584 .build();
585
586 TrafficTreatment downstreamTreatment = DefaultTrafficTreatment.builder()
587 .pushVlan()
588 .setVlanId(VLAN_WAN)
589 .setEthDst(vSgHost.mac())
590 .setOutput(vSgHost.location().port())
591 .build();
592
593 FlowRule downstreamFlowRule = DefaultFlowRule.builder()
594 .fromApp(appId)
595 .withSelector(downstream)
596 .withTreatment(downstreamTreatment)
597 .withPriority(DEFAULT_PRIORITY)
598 .forDevice(vSgHost.location().deviceId())
599 .forTable(TABLE_DST_IP)
600 .makePermanent()
601 .build();
602
603 processFlowRule(true, downstreamFlowRule);
604 });
605
606 // remove downstream flow rules for the vSG not shown in vSgIps
607 for (FlowRule rule : flowRuleService.getFlowRulesById(appId)) {
608 if (!rule.deviceId().equals(vSgHost.location().deviceId())) {
609 continue;
610 }
611 PortNumber output = getOutputFromTreatment(rule);
612 if (output == null || !output.equals(vSgHost.location().port()) ||
613 !isVlanPushFromTreatment(rule)) {
614 continue;
615 }
616
617 IpPrefix dstIp = getDstIpFromSelector(rule);
618 if (dstIp != null && !vSgIps.contains(dstIp.address())) {
619 processFlowRule(false, rule);
620 }
621 }
622 }
623
624 /**
Hyunsun Moon4a915152016-01-14 16:56:26 -0800625 * Populates default rules on the first table.
Hyunsun Moon133fd792016-02-09 01:55:48 -0800626 * It includes the rules for shuttling vxlan-encapped packets between ovs and
627 * linux stack,and external network connectivity.
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800628 *
629 * @param deviceId device id
Hyunsun Moon133fd792016-02-09 01:55:48 -0800630 * @param dpPort data plane interface port number
631 * @param dpIp data plane ip address
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800632 */
Hyunsun Moon133fd792016-02-09 01:55:48 -0800633 private void processFirstTable(DeviceId deviceId, PortNumber dpPort, IpAddress dpIp) {
Hyunsun Moon4a915152016-01-14 16:56:26 -0800634 // take vxlan packet out onto the physical port
635 TrafficSelector selector = DefaultTrafficSelector.builder()
636 .matchInPort(PortNumber.LOCAL)
637 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800638
Hyunsun Moon4a915152016-01-14 16:56:26 -0800639 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Hyunsun Moon133fd792016-02-09 01:55:48 -0800640 .setOutput(dpPort)
Hyunsun Moon4a915152016-01-14 16:56:26 -0800641 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800642
Hyunsun Moon4a915152016-01-14 16:56:26 -0800643 FlowRule flowRule = DefaultFlowRule.builder()
644 .fromApp(appId)
645 .withSelector(selector)
646 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800647 .withPriority(HIGH_PRIORITY)
Hyunsun Moon4a915152016-01-14 16:56:26 -0800648 .forDevice(deviceId)
649 .forTable(TABLE_FIRST)
650 .makePermanent()
651 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800652
Hyunsun Moon4a915152016-01-14 16:56:26 -0800653 processFlowRule(true, flowRule);
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800654
Hyunsun Moon4a915152016-01-14 16:56:26 -0800655 // take a vxlan encap'd packet through the Linux stack
656 selector = DefaultTrafficSelector.builder()
Hyunsun Moon133fd792016-02-09 01:55:48 -0800657 .matchInPort(dpPort)
Hyunsun Moon4a915152016-01-14 16:56:26 -0800658 .matchEthType(Ethernet.TYPE_IPV4)
659 .matchIPProtocol(IPv4.PROTOCOL_UDP)
660 .matchUdpDst(TpPort.tpPort(VXLAN_UDP_PORT))
661 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800662
Hyunsun Moon4a915152016-01-14 16:56:26 -0800663 treatment = DefaultTrafficTreatment.builder()
664 .setOutput(PortNumber.LOCAL)
665 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800666
Hyunsun Moon4a915152016-01-14 16:56:26 -0800667 flowRule = DefaultFlowRule.builder()
668 .fromApp(appId)
669 .withSelector(selector)
670 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800671 .withPriority(HIGH_PRIORITY)
Hyunsun Moon4a915152016-01-14 16:56:26 -0800672 .forDevice(deviceId)
673 .forTable(TABLE_FIRST)
674 .makePermanent()
675 .build();
676
677 processFlowRule(true, flowRule);
678
Hyunsun Moon133fd792016-02-09 01:55:48 -0800679 // take a packet to the data plane ip through Linux stack
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800680 selector = DefaultTrafficSelector.builder()
Hyunsun Moon133fd792016-02-09 01:55:48 -0800681 .matchInPort(dpPort)
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800682 .matchEthType(Ethernet.TYPE_IPV4)
Hyunsun Moon133fd792016-02-09 01:55:48 -0800683 .matchIPDst(dpIp.toIpPrefix())
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800684 .build();
685
686 treatment = DefaultTrafficTreatment.builder()
687 .setOutput(PortNumber.LOCAL)
688 .build();
689
690 flowRule = DefaultFlowRule.builder()
691 .fromApp(appId)
692 .withSelector(selector)
693 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800694 .withPriority(HIGH_PRIORITY)
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800695 .forDevice(deviceId)
696 .forTable(TABLE_FIRST)
697 .makePermanent()
698 .build();
699
700 processFlowRule(true, flowRule);
701
702 // take an arp packet from physical through Linux stack
703 selector = DefaultTrafficSelector.builder()
Hyunsun Moon133fd792016-02-09 01:55:48 -0800704 .matchInPort(dpPort)
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800705 .matchEthType(Ethernet.TYPE_ARP)
Hyunsun Moon6d247342016-02-12 12:48:47 -0800706 .matchArpTpa(dpIp.getIp4Address())
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800707 .build();
708
709 treatment = DefaultTrafficTreatment.builder()
710 .setOutput(PortNumber.LOCAL)
711 .build();
712
713 flowRule = DefaultFlowRule.builder()
714 .fromApp(appId)
715 .withSelector(selector)
716 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800717 .withPriority(HIGH_PRIORITY)
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800718 .forDevice(deviceId)
719 .forTable(TABLE_FIRST)
720 .makePermanent()
721 .build();
722
723 processFlowRule(true, flowRule);
724
Hyunsun Moon4a915152016-01-14 16:56:26 -0800725 // take all else to the next table
726 selector = DefaultTrafficSelector.builder()
727 .build();
728
729 treatment = DefaultTrafficTreatment.builder()
730 .transition(TABLE_IN_PORT)
731 .build();
732
733 flowRule = DefaultFlowRule.builder()
734 .fromApp(appId)
735 .withSelector(selector)
736 .withTreatment(treatment)
737 .withPriority(LOWEST_PRIORITY)
738 .forDevice(deviceId)
739 .forTable(TABLE_FIRST)
740 .makePermanent()
741 .build();
742
743 processFlowRule(true, flowRule);
Hyunsun Moon6d247342016-02-12 12:48:47 -0800744
745 // take all vlan tagged packet to the Q_IN_Q table
746 selector = DefaultTrafficSelector.builder()
747 .matchVlanId(VlanId.ANY)
748 .build();
749
750 treatment = DefaultTrafficTreatment.builder()
751 .transition(TABLE_Q_IN_Q)
752 .build();
753
754 flowRule = DefaultFlowRule.builder()
755 .fromApp(appId)
756 .withSelector(selector)
757 .withTreatment(treatment)
758 .withPriority(VSG_PRIORITY)
759 .forDevice(deviceId)
760 .forTable(TABLE_FIRST)
761 .makePermanent()
762 .build();
763
764 processFlowRule(true, flowRule);
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800765 }
766
767 /**
Hyunsun Moon133fd792016-02-09 01:55:48 -0800768 * Forward table miss packets in ACCESS_TYPE table to data plane port.
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800769 *
770 * @param deviceId device id
Hyunsun Moon133fd792016-02-09 01:55:48 -0800771 * @param dpPort data plane interface port number
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800772 */
Hyunsun Moon133fd792016-02-09 01:55:48 -0800773 private void processAccessTypeTable(DeviceId deviceId, PortNumber dpPort) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800774 TrafficSelector selector = DefaultTrafficSelector.builder()
775 .build();
776
777 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Hyunsun Moon133fd792016-02-09 01:55:48 -0800778 .setOutput(dpPort)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800779 .build();
780
781 FlowRule flowRule = DefaultFlowRule.builder()
782 .fromApp(appId)
783 .withSelector(selector)
784 .withTreatment(treatment)
785 .withPriority(LOWEST_PRIORITY)
786 .forDevice(deviceId)
787 .forTable(TABLE_ACCESS_TYPE)
788 .makePermanent()
789 .build();
790
791 processFlowRule(true, flowRule);
792 }
793
794 /**
Hyunsun Moon4a915152016-01-14 16:56:26 -0800795 * Populates default rules for IN_PORT table.
796 * All packets from tunnel port are forwarded to TUNNEL_ID table and all packets
Hyunsun Moon133fd792016-02-09 01:55:48 -0800797 * from data plane interface port to ACCESS_TYPE table.
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800798 *
799 * @param deviceId device id to install the rules
Hyunsun Moon4a915152016-01-14 16:56:26 -0800800 * @param tunnelPort tunnel port number
Hyunsun Moon133fd792016-02-09 01:55:48 -0800801 * @param dpPort data plane interface port number
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800802 */
Hyunsun Moon133fd792016-02-09 01:55:48 -0800803 private void processInPortTable(DeviceId deviceId, PortNumber tunnelPort, PortNumber dpPort) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800804 checkNotNull(tunnelPort);
805
806 TrafficSelector selector = DefaultTrafficSelector.builder()
807 .matchInPort(tunnelPort)
808 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800809
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800810 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
811 .transition(TABLE_TUNNEL_IN)
812 .build();
813
814 FlowRule flowRule = DefaultFlowRule.builder()
815 .fromApp(appId)
816 .withSelector(selector)
817 .withTreatment(treatment)
818 .withPriority(DEFAULT_PRIORITY)
819 .forDevice(deviceId)
820 .forTable(TABLE_IN_PORT)
821 .makePermanent()
822 .build();
823
824 processFlowRule(true, flowRule);
Hyunsun Moon4a915152016-01-14 16:56:26 -0800825
826 selector = DefaultTrafficSelector.builder()
Hyunsun Moon133fd792016-02-09 01:55:48 -0800827 .matchInPort(dpPort)
Hyunsun Moon4a915152016-01-14 16:56:26 -0800828 .build();
829
830 treatment = DefaultTrafficTreatment.builder()
831 .transition(TABLE_DST_IP)
832 .build();
833
834 flowRule = DefaultFlowRule.builder()
835 .fromApp(appId)
836 .withSelector(selector)
837 .withTreatment(treatment)
838 .withPriority(DEFAULT_PRIORITY)
839 .forDevice(deviceId)
840 .forTable(TABLE_IN_PORT)
841 .makePermanent()
842 .build();
843
844 processFlowRule(true, flowRule);
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800845 }
846
847 /**
Hyunsun Moon6d247342016-02-12 12:48:47 -0800848 * Populates default rules for Q_IN_Q table.
849 *
850 * @param deviceId device id
851 * @param dpPort data plane interface port number
852 */
853 private void processQInQTable(DeviceId deviceId, PortNumber dpPort) {
854 // for traffic going out to WAN, strip vid 500 and take through data plane interface
855 TrafficSelector selector = DefaultTrafficSelector.builder()
856 .matchVlanId(VLAN_WAN)
857 .build();
858
859 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
860 .popVlan()
861 .setOutput(dpPort)
862 .build();
863
864 FlowRule flowRule = DefaultFlowRule.builder()
865 .fromApp(appId)
866 .withSelector(selector)
867 .withTreatment(treatment)
868 .withPriority(DEFAULT_PRIORITY)
869 .forDevice(deviceId)
870 .forTable(TABLE_Q_IN_Q)
871 .makePermanent()
872 .build();
873
874 processFlowRule(true, flowRule);
875
876 selector = DefaultTrafficSelector.builder()
877 .matchVlanId(VLAN_WAN)
878 .matchEthType(Ethernet.TYPE_ARP)
879 .build();
880
881 treatment = DefaultTrafficTreatment.builder()
882 .setOutput(PortNumber.CONTROLLER)
883 .build();
884
885 flowRule = DefaultFlowRule.builder()
886 .fromApp(appId)
887 .withSelector(selector)
888 .withTreatment(treatment)
889 .withPriority(HIGH_PRIORITY)
890 .forDevice(deviceId)
891 .forTable(TABLE_Q_IN_Q)
892 .makePermanent()
893 .build();
894
895 processFlowRule(true, flowRule);
896 }
897
898 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800899 * Populates rules for local in port in IN_PORT table.
900 * Flows from a given in port, whose source IP is service IP transition
901 * to DST_TYPE table. Other flows transition to IN_SERVICE table.
902 *
903 * @param deviceId device id to install the rules
904 * @param inPort in port
905 * @param srcIp source ip
906 */
907 private void populateLocalInPortRule(DeviceId deviceId, PortNumber inPort, IpAddress srcIp) {
908 TrafficSelector selector = DefaultTrafficSelector.builder()
909 .matchInPort(inPort)
910 .matchEthType(Ethernet.TYPE_IPV4)
911 .matchIPSrc(srcIp.toIpPrefix())
912 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800913
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800914 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
915 .transition(TABLE_ACCESS_TYPE)
916 .build();
917
918
919 FlowRule flowRule = DefaultFlowRule.builder()
920 .fromApp(appId)
921 .withSelector(selector)
922 .withTreatment(treatment)
923 .withPriority(DEFAULT_PRIORITY)
924 .forDevice(deviceId)
925 .forTable(TABLE_IN_PORT)
926 .makePermanent()
927 .build();
928
929 processFlowRule(true, flowRule);
930
931 selector = DefaultTrafficSelector.builder()
932 .matchInPort(inPort)
933 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800934
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800935 treatment = DefaultTrafficTreatment.builder()
936 .transition(TABLE_IN_SERVICE)
937 .build();
938
939 flowRule = DefaultFlowRule.builder()
940 .fromApp(appId)
941 .withSelector(selector)
942 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -0800943 .withPriority(LOW_PRIORITY)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800944 .forDevice(deviceId)
945 .forTable(TABLE_IN_PORT)
946 .makePermanent()
947 .build();
948
949 processFlowRule(true, flowRule);
950 }
951
952 /**
953 * Populates direct VM access rules for ACCESS_TYPE table.
954 * These rules are installed to all devices.
955 *
956 * @param srcRange source ip range
957 * @param dstRange destination ip range
958 */
959 private void populateDirectAccessRule(Ip4Prefix srcRange, Ip4Prefix dstRange) {
960 TrafficSelector selector = DefaultTrafficSelector.builder()
961 .matchEthType(Ethernet.TYPE_IPV4)
962 .matchIPSrc(srcRange)
963 .matchIPDst(dstRange)
964 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800965
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800966 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
967 .transition(TABLE_DST_IP)
968 .build();
969
970 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
Hyunsun Moon98025542016-03-08 04:36:02 -0800971 if (!device.hwVersion().equals(OVS_HW_VERSION)) {
972 continue;
973 }
974
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800975 FlowRule flowRuleDirect = DefaultFlowRule.builder()
976 .fromApp(appId)
977 .withSelector(selector)
978 .withTreatment(treatment)
Hyunsun Moon81ab23b2016-02-01 23:00:56 -0800979 .withPriority(DEFAULT_PRIORITY)
980 .forDevice(device.id())
981 .forTable(TABLE_ACCESS_TYPE)
982 .makePermanent()
983 .build();
984
985 processFlowRule(true, flowRuleDirect);
986 }
987 }
988
989 /**
990 * Populates drop rules that does not match any direct access rules but has
991 * destination to a different service network in ACCESS_TYPE table.
992 *
993 * @param dstRange destination ip range
994 */
995 private void populateServiceIsolationRule(Ip4Prefix dstRange) {
996 TrafficSelector selector = DefaultTrafficSelector.builder()
997 .matchEthType(Ethernet.TYPE_IPV4)
998 .matchIPDst(dstRange)
999 .build();
1000
1001 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
1002 .drop()
1003 .build();
1004
1005 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
Hyunsun Moon98025542016-03-08 04:36:02 -08001006 if (!device.hwVersion().equals(OVS_HW_VERSION)) {
1007 continue;
1008 }
1009
Hyunsun Moon81ab23b2016-02-01 23:00:56 -08001010 FlowRule flowRuleDirect = DefaultFlowRule.builder()
1011 .fromApp(appId)
1012 .withSelector(selector)
1013 .withTreatment(treatment)
Hyunsun Moond52bffc2016-01-29 18:57:05 -08001014 .withPriority(LOW_PRIORITY)
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001015 .forDevice(device.id())
1016 .forTable(TABLE_ACCESS_TYPE)
1017 .makePermanent()
1018 .build();
1019
1020 processFlowRule(true, flowRuleDirect);
1021 }
1022 }
1023
1024 /**
1025 * Populates indirect service access rules for ACCESS_TYPE table.
1026 * These rules are installed to all devices.
1027 *
1028 * @param srcRange source range
1029 * @param serviceIp service ip
1030 * @param outGroups list of output group
1031 */
1032 private void populateIndirectAccessRule(Ip4Prefix srcRange, Ip4Address serviceIp,
1033 Map<DeviceId, GroupId> outGroups) {
1034 TrafficSelector selector = DefaultTrafficSelector.builder()
1035 .matchEthType(Ethernet.TYPE_IPV4)
1036 .matchIPSrc(srcRange)
1037 .matchIPDst(serviceIp.toIpPrefix())
1038 .build();
1039
1040 for (Map.Entry<DeviceId, GroupId> outGroup : outGroups.entrySet()) {
1041 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
1042 .group(outGroup.getValue())
1043 .build();
1044
1045 FlowRule flowRule = DefaultFlowRule.builder()
1046 .fromApp(appId)
1047 .withSelector(selector)
1048 .withTreatment(treatment)
Hyunsun Moon81ab23b2016-02-01 23:00:56 -08001049 .withPriority(HIGH_PRIORITY)
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001050 .forDevice(outGroup.getKey())
1051 .forTable(TABLE_ACCESS_TYPE)
1052 .makePermanent()
1053 .build();
1054
1055 processFlowRule(true, flowRule);
1056 }
1057 }
1058
1059 /**
1060 * Populates flow rules for IN_SERVICE table.
1061 *
1062 * @param inPorts list of inports related to the service for each device
1063 * @param outGroups set of output groups
1064 */
1065 private void populateInServiceRule(Map<DeviceId, Set<PortNumber>> inPorts, Map<DeviceId, GroupId> outGroups) {
1066 checkNotNull(inPorts);
1067 checkNotNull(outGroups);
1068
1069 for (Map.Entry<DeviceId, Set<PortNumber>> entry : inPorts.entrySet()) {
1070 Set<PortNumber> ports = entry.getValue();
1071 DeviceId deviceId = entry.getKey();
1072
1073 GroupId groupId = outGroups.get(deviceId);
1074 if (groupId == null) {
1075 continue;
1076 }
1077
1078 ports.stream().forEach(port -> {
1079 TrafficSelector selector = DefaultTrafficSelector.builder()
1080 .matchInPort(port)
1081 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -08001082
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001083 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
1084 .group(groupId)
1085 .build();
1086
1087 FlowRule flowRule = DefaultFlowRule.builder()
1088 .fromApp(appId)
1089 .withSelector(selector)
1090 .withTreatment(treatment)
1091 .withPriority(DEFAULT_PRIORITY)
1092 .forDevice(deviceId)
1093 .forTable(TABLE_IN_SERVICE)
1094 .makePermanent()
1095 .build();
1096
1097 processFlowRule(true, flowRule);
1098 });
1099 }
1100 }
1101
1102 /**
1103 * Populates flow rules for DST_IP table.
1104 *
1105 * @param deviceId device id
1106 * @param inPort in port
1107 * @param dstMac mac address
1108 * @param dstIp destination ip
1109 * @param tunnelId tunnel id
1110 * @param tunnelIp tunnel remote ip
1111 */
1112 private void populateDstIpRule(DeviceId deviceId, PortNumber inPort, MacAddress dstMac,
1113 IpAddress dstIp, long tunnelId, IpAddress tunnelIp) {
1114 TrafficSelector selector = DefaultTrafficSelector.builder()
1115 .matchEthType(Ethernet.TYPE_IPV4)
1116 .matchIPDst(dstIp.toIpPrefix())
1117 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -08001118
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001119 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
1120 .setEthDst(dstMac)
1121 .setOutput(inPort)
1122 .build();
1123
1124 FlowRule flowRule = DefaultFlowRule.builder()
1125 .fromApp(appId)
1126 .withSelector(selector)
1127 .withTreatment(treatment)
1128 .withPriority(DEFAULT_PRIORITY)
1129 .forDevice(deviceId)
1130 .forTable(TABLE_DST_IP)
1131 .makePermanent()
1132 .build();
1133
1134 processFlowRule(true, flowRule);
1135
1136 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
Hyunsun Moon98025542016-03-08 04:36:02 -08001137 if (!device.hwVersion().equals(OVS_HW_VERSION)) {
1138 continue;
1139 }
1140
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001141 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