blob: ad9dee8e2794ab1f2525faea63b3dbdd62030df9 [file] [log] [blame]
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.cordvtn;
17
Hyunsun Moonc71231d2015-12-16 20:53:23 -080018import com.google.common.collect.Lists;
19import com.google.common.collect.Maps;
20import org.onlab.packet.Ethernet;
Hyunsun Moon4a915152016-01-14 16:56:26 -080021import org.onlab.packet.IPv4;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080022import org.onlab.packet.Ip4Address;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080023import org.onlab.packet.Ip4Prefix;
24import org.onlab.packet.IpAddress;
25import org.onlab.packet.IpPrefix;
26import org.onlab.packet.MacAddress;
Hyunsun Moon4a915152016-01-14 16:56:26 -080027import org.onlab.packet.TpPort;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080028import org.onlab.util.ItemNotFoundException;
29import org.onosproject.core.ApplicationId;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080030import org.onosproject.core.DefaultGroupId;
31import org.onosproject.core.GroupId;
32import org.onosproject.mastership.MastershipService;
33import org.onosproject.net.Device;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080034import org.onosproject.net.DeviceId;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080035import org.onosproject.net.Host;
Hyunsun Moon5a4346f2016-01-15 11:41:14 -080036import org.onosproject.net.Port;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080037import org.onosproject.net.PortNumber;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080038import org.onosproject.net.behaviour.ExtensionTreatmentResolver;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080039import org.onosproject.net.device.DeviceService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080040import org.onosproject.net.driver.DefaultDriverData;
41import org.onosproject.net.driver.DefaultDriverHandler;
42import org.onosproject.net.driver.Driver;
43import org.onosproject.net.driver.DriverHandler;
44import org.onosproject.net.driver.DriverService;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080045import org.onosproject.net.flow.DefaultFlowRule;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080046import org.onosproject.net.flow.DefaultTrafficSelector;
47import org.onosproject.net.flow.DefaultTrafficTreatment;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080048import org.onosproject.net.flow.FlowRule;
49import org.onosproject.net.flow.FlowRuleOperations;
50import org.onosproject.net.flow.FlowRuleOperationsContext;
51import org.onosproject.net.flow.FlowRuleService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080052import org.onosproject.net.flow.TrafficSelector;
53import org.onosproject.net.flow.TrafficTreatment;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080054import org.onosproject.net.flow.criteria.Criterion;
55import org.onosproject.net.flow.criteria.EthCriterion;
56import org.onosproject.net.flow.criteria.IPCriterion;
57import org.onosproject.net.flow.criteria.PortCriterion;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080058import org.onosproject.net.flow.instructions.ExtensionPropertyException;
59import org.onosproject.net.flow.instructions.ExtensionTreatment;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080060import org.onosproject.net.flow.instructions.Instruction;
61import org.onosproject.net.flow.instructions.Instructions;
62import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
63import org.onosproject.net.group.DefaultGroupBucket;
64import org.onosproject.net.group.DefaultGroupDescription;
65import org.onosproject.net.group.DefaultGroupKey;
66import org.onosproject.net.group.Group;
67import org.onosproject.net.group.GroupBucket;
68import org.onosproject.net.group.GroupBuckets;
69import org.onosproject.net.group.GroupDescription;
70import org.onosproject.net.group.GroupKey;
71import org.onosproject.net.group.GroupService;
72import org.onosproject.openstackswitching.OpenstackNetwork;
73import org.onosproject.openstackswitching.OpenstackSubnet;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080074import org.slf4j.Logger;
75
Hyunsun Moon4161e6f2016-01-07 01:32:31 -080076import java.util.ArrayList;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080077import java.util.List;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080078import java.util.Map;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080079import java.util.Objects;
80import java.util.Set;
81import java.util.stream.Collectors;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080082
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080083import static com.google.common.base.Preconditions.checkNotNull;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080084import static org.onosproject.net.Device.Type.SWITCH;
85import static org.onosproject.net.flow.criteria.Criterion.Type.IN_PORT;
86import static org.onosproject.net.flow.criteria.Criterion.Type.IPV4_DST;
87import static org.onosproject.net.flow.criteria.Criterion.Type.IPV4_SRC;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080088import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST;
Hyunsun Moonc71231d2015-12-16 20:53:23 -080089import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.ETH_DST;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080090import static org.slf4j.LoggerFactory.getLogger;
91
92/**
Hyunsun Moonc71231d2015-12-16 20:53:23 -080093 * Populates rules for CORD VTN service.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080094 */
Hyunsun Moonc71231d2015-12-16 20:53:23 -080095public class CordVtnRuleInstaller {
96
Hyunsun Moon9f0814b2015-11-04 17:34:35 -080097 protected final Logger log = getLogger(getClass());
98
Hyunsun Moon4a915152016-01-14 16:56:26 -080099 private static final int TABLE_FIRST = 0;
100 private static final int TABLE_IN_PORT = 1;
101 private static final int TABLE_ACCESS_TYPE = 2;
102 private static final int TABLE_IN_SERVICE = 3;
103 private static final int TABLE_DST_IP = 4;
104 private static final int TABLE_TUNNEL_IN = 5;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800105
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800106 private static final int DEFAULT_PRIORITY = 5000;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800107 private static final int LOWER_PRIORITY = 4000;
108 private static final int LOWEST_PRIORITY = 0;
Hyunsun Moon4a915152016-01-14 16:56:26 -0800109 private static final int HIGHER_PRIORITY = 50000;
110
111 private static final int VXLAN_UDP_PORT = 4789;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800112
113 private final ApplicationId appId;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800114 private final FlowRuleService flowRuleService;
115 private final DeviceService deviceService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800116 private final DriverService driverService;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800117 private final GroupService groupService;
118 private final MastershipService mastershipService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800119 private final String tunnelType;
120
121 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800122 * Creates a new rule populator.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800123 *
124 * @param appId application id
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800125 * @param flowRuleService flow rule service
126 * @param deviceService device service
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800127 * @param driverService driver service
Jian Lidfba7392016-01-22 16:46:58 -0800128 * @param groupService group service
129 * @param mastershipService mastership service
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800130 * @param tunnelType tunnel type
131 */
132 public CordVtnRuleInstaller(ApplicationId appId,
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800133 FlowRuleService flowRuleService,
134 DeviceService deviceService,
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800135 DriverService driverService,
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800136 GroupService groupService,
137 MastershipService mastershipService,
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800138 String tunnelType) {
139 this.appId = appId;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800140 this.flowRuleService = flowRuleService;
141 this.deviceService = deviceService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800142 this.driverService = driverService;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800143 this.groupService = groupService;
144 this.mastershipService = mastershipService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800145 this.tunnelType = checkNotNull(tunnelType);
146 }
147
148 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800149 * Installs table miss rule to a give device.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800150 *
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800151 * @param deviceId device id to install the rules
Hyunsun Moon4a915152016-01-14 16:56:26 -0800152 * @param phyPortName physical port name
153 * @param localIp local data plane ip address
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800154 */
Hyunsun Moon4a915152016-01-14 16:56:26 -0800155 public void init(DeviceId deviceId, String phyPortName, IpAddress localIp) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800156 // default is drop packets which can be accomplished without
157 // a table miss entry for all table.
Hyunsun Moon4a915152016-01-14 16:56:26 -0800158 PortNumber tunnelPort = getTunnelPort(deviceId);
159 PortNumber phyPort = getPhyPort(deviceId, phyPortName);
160
161 processFirstTable(deviceId, phyPort, localIp);
162 processInPortTable(deviceId, tunnelPort, phyPort);
163 processAccessTypeTable(deviceId, phyPort);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800164 }
165
166 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800167 * Populates basic rules that connect a VM to the other VMs in the system.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800168 *
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800169 * @param host host
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800170 * @param tunnelIp tunnel ip
171 * @param vNet openstack network
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800172 */
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800173 public void populateBasicConnectionRules(Host host, IpAddress tunnelIp, OpenstackNetwork vNet) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800174 checkNotNull(host);
175 checkNotNull(vNet);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800176
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800177 DeviceId deviceId = host.location().deviceId();
178 if (!mastershipService.isLocalMaster(deviceId)) {
179 return;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800180 }
181
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800182 PortNumber inPort = host.location().port();
183 MacAddress dstMac = host.mac();
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800184 IpAddress hostIp = host.ipAddresses().stream().findFirst().get();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800185 long tunnelId = Long.parseLong(vNet.segmentId());
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800186
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800187 OpenstackSubnet subnet = vNet.subnets().stream()
188 .findFirst()
189 .orElse(null);
190
191 if (subnet == null) {
192 log.error("Failed to get subnet for {}", host.id());
193 return;
194 }
195
196 populateLocalInPortRule(deviceId, inPort, hostIp);
197 populateDirectAccessRule(Ip4Prefix.valueOf(subnet.cidr()), Ip4Prefix.valueOf(subnet.cidr()));
198 populateDstIpRule(deviceId, inPort, dstMac, hostIp, tunnelId, tunnelIp);
199 populateTunnelInRule(deviceId, inPort, dstMac, tunnelId);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800200 }
201
202 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800203 * Removes basic rules related to a given flow information.
204 *
205 * @param host host to be removed
206 */
207 public void removeBasicConnectionRules(Host host) {
208 checkNotNull(host);
209
210 DeviceId deviceId = host.location().deviceId();
211 MacAddress mac = host.mac();
212 PortNumber port = host.location().port();
213 IpAddress ip = host.ipAddresses().stream().findFirst().orElse(null);
214
215 if (!mastershipService.isLocalMaster(deviceId)) {
216 return;
217 }
218
219 for (FlowRule flowRule : flowRuleService.getFlowRulesById(appId)) {
220 if (flowRule.deviceId().equals(deviceId)) {
221 PortNumber inPort = getInPort(flowRule);
222 if (inPort != null && inPort.equals(port)) {
223 processFlowRule(false, flowRule);
224 continue;
225 }
226 }
227
228 MacAddress dstMac = getDstMacFromTreatment(flowRule);
229 if (dstMac != null && dstMac.equals(mac)) {
230 processFlowRule(false, flowRule);
231 continue;
232 }
233
234 dstMac = getDstMacFromSelector(flowRule);
235 if (dstMac != null && dstMac.equals(mac)) {
236 processFlowRule(false, flowRule);
237 continue;
238 }
239
240 IpPrefix dstIp = getDstIpFromSelector(flowRule);
241 if (dstIp != null && dstIp.equals(ip.toIpPrefix())) {
242 processFlowRule(false, flowRule);
243 }
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800244 }
245
246 // TODO uninstall same network access rule in access table if no vm exists in the network
247 }
248
249 /**
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800250 * Populates service dependency rules.
251 *
252 * @param tService tenant cord service
253 * @param pService provider cord service
254 */
255 public void populateServiceDependencyRules(CordService tService, CordService pService) {
256 checkNotNull(tService);
257 checkNotNull(pService);
258
259 Ip4Prefix srcRange = tService.serviceIpRange().getIp4Prefix();
260 Ip4Prefix dstRange = pService.serviceIpRange().getIp4Prefix();
261 Ip4Address serviceIp = pService.serviceIp().getIp4Address();
262
263 Map<DeviceId, GroupId> outGroups = Maps.newHashMap();
264 Map<DeviceId, Set<PortNumber>> inPorts = Maps.newHashMap();
265
266 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
267 GroupId groupId = createServiceGroup(device.id(), pService);
268 outGroups.put(device.id(), groupId);
269
270 Set<PortNumber> vms = tService.hosts().keySet()
271 .stream()
272 .filter(host -> host.location().deviceId().equals(device.id()))
273 .map(host -> host.location().port())
274 .collect(Collectors.toSet());
275 inPorts.put(device.id(), vms);
276 }
277
278 populateIndirectAccessRule(srcRange, serviceIp, outGroups);
279 populateDirectAccessRule(srcRange, dstRange);
280 populateInServiceRule(inPorts, outGroups);
281 }
282
283 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800284 * Removes service dependency rules.
285 *
286 * @param tService tenant cord service
287 * @param pService provider cord service
288 */
289 public void removeServiceDependencyRules(CordService tService, CordService pService) {
290 checkNotNull(tService);
291 checkNotNull(pService);
292
293 Ip4Prefix srcRange = tService.serviceIpRange().getIp4Prefix();
294 Ip4Prefix dstRange = pService.serviceIpRange().getIp4Prefix();
295 IpPrefix serviceIp = pService.serviceIp().toIpPrefix();
296
297 Map<DeviceId, GroupId> outGroups = Maps.newHashMap();
298 GroupKey groupKey = new DefaultGroupKey(pService.id().id().getBytes());
299
300 deviceService.getAvailableDevices(SWITCH).forEach(device -> {
301 Group group = groupService.getGroup(device.id(), groupKey);
302 if (group != null) {
303 outGroups.put(device.id(), group.id());
304 }
305 });
306
307 for (FlowRule flowRule : flowRuleService.getFlowRulesById(appId)) {
308 IpPrefix dstIp = getDstIpFromSelector(flowRule);
309 IpPrefix srcIp = getSrcIpFromSelector(flowRule);
310
311 if (dstIp != null && dstIp.equals(serviceIp)) {
312 processFlowRule(false, flowRule);
313 continue;
314 }
315
316 if (dstIp != null && srcIp != null) {
317 if (dstIp.equals(dstRange) && srcIp.equals(srcRange)) {
318 processFlowRule(false, flowRule);
319 continue;
320 }
321
322 if (dstIp.equals(srcRange) && srcIp.equals(dstRange)) {
323 processFlowRule(false, flowRule);
324 continue;
325 }
326 }
327
328 GroupId groupId = getGroupIdFromTreatment(flowRule);
329 if (groupId != null && groupId.equals(outGroups.get(flowRule.deviceId()))) {
330 processFlowRule(false, flowRule);
331 }
332 }
333
334 // TODO remove the group if it is not in use
335 }
336
337 /**
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800338 * Updates group buckets for a given service to all devices.
339 *
340 * @param service cord service
341 */
342 public void updateServiceGroup(CordService service) {
343 checkNotNull(service);
344
345 GroupKey groupKey = getGroupKey(service.id());
346
347 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
348 DeviceId deviceId = device.id();
349 if (!mastershipService.isLocalMaster(deviceId)) {
350 continue;
351 }
352
353 Group group = groupService.getGroup(deviceId, groupKey);
354 if (group == null) {
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800355 log.trace("No group exists for service {} in {}, do nothing.", service.id(), deviceId);
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800356 continue;
357 }
358
359 List<GroupBucket> oldBuckets = group.buckets().buckets();
360 List<GroupBucket> newBuckets = getServiceGroupBuckets(
361 deviceId, service.segmentationId(), service.hosts()).buckets();
362
363 if (oldBuckets.equals(newBuckets)) {
364 continue;
365 }
366
367 List<GroupBucket> bucketsToRemove = new ArrayList<>(oldBuckets);
368 bucketsToRemove.removeAll(newBuckets);
369 if (!bucketsToRemove.isEmpty()) {
370 groupService.removeBucketsFromGroup(
371 deviceId,
372 groupKey,
373 new GroupBuckets(bucketsToRemove),
374 groupKey, appId);
375 }
376
377 List<GroupBucket> bucketsToAdd = new ArrayList<>(newBuckets);
378 bucketsToAdd.removeAll(oldBuckets);
379 if (!bucketsToAdd.isEmpty()) {
380 groupService.addBucketsToGroup(
381 deviceId,
382 groupKey,
383 new GroupBuckets(bucketsToAdd),
384 groupKey, appId);
385 }
386 }
387 }
388
389 /**
Hyunsun Moon4a915152016-01-14 16:56:26 -0800390 * Populates default rules on the first table.
391 * The rules are for shuttling vxlan-encapped packets and supporting physical
392 * network connectivity.
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800393 *
394 * @param deviceId device id
Hyunsun Moon4a915152016-01-14 16:56:26 -0800395 * @param phyPort physical port number
396 * @param localIp local data plane ip address
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800397 */
Hyunsun Moon4a915152016-01-14 16:56:26 -0800398 private void processFirstTable(DeviceId deviceId, PortNumber phyPort, IpAddress localIp) {
399 // take vxlan packet out onto the physical port
400 TrafficSelector selector = DefaultTrafficSelector.builder()
401 .matchInPort(PortNumber.LOCAL)
402 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800403
Hyunsun Moon4a915152016-01-14 16:56:26 -0800404 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
405 .setOutput(phyPort)
406 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800407
Hyunsun Moon4a915152016-01-14 16:56:26 -0800408 FlowRule flowRule = DefaultFlowRule.builder()
409 .fromApp(appId)
410 .withSelector(selector)
411 .withTreatment(treatment)
412 .withPriority(HIGHER_PRIORITY)
413 .forDevice(deviceId)
414 .forTable(TABLE_FIRST)
415 .makePermanent()
416 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800417
Hyunsun Moon4a915152016-01-14 16:56:26 -0800418 processFlowRule(true, flowRule);
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800419
Hyunsun Moon4a915152016-01-14 16:56:26 -0800420 // take a vxlan encap'd packet through the Linux stack
421 selector = DefaultTrafficSelector.builder()
422 .matchInPort(phyPort)
423 .matchEthType(Ethernet.TYPE_IPV4)
424 .matchIPProtocol(IPv4.PROTOCOL_UDP)
425 .matchUdpDst(TpPort.tpPort(VXLAN_UDP_PORT))
426 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800427
Hyunsun Moon4a915152016-01-14 16:56:26 -0800428 treatment = DefaultTrafficTreatment.builder()
429 .setOutput(PortNumber.LOCAL)
430 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800431
Hyunsun Moon4a915152016-01-14 16:56:26 -0800432 flowRule = DefaultFlowRule.builder()
433 .fromApp(appId)
434 .withSelector(selector)
435 .withTreatment(treatment)
436 .withPriority(HIGHER_PRIORITY)
437 .forDevice(deviceId)
438 .forTable(TABLE_FIRST)
439 .makePermanent()
440 .build();
441
442 processFlowRule(true, flowRule);
443
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800444 // take a packet to the local ip through Linux stack
445 selector = DefaultTrafficSelector.builder()
446 .matchInPort(phyPort)
447 .matchEthType(Ethernet.TYPE_IPV4)
448 .matchIPDst(localIp.toIpPrefix())
449 .build();
450
451 treatment = DefaultTrafficTreatment.builder()
452 .setOutput(PortNumber.LOCAL)
453 .build();
454
455 flowRule = DefaultFlowRule.builder()
456 .fromApp(appId)
457 .withSelector(selector)
458 .withTreatment(treatment)
459 .withPriority(HIGHER_PRIORITY)
460 .forDevice(deviceId)
461 .forTable(TABLE_FIRST)
462 .makePermanent()
463 .build();
464
465 processFlowRule(true, flowRule);
466
467 // take an arp packet from physical through Linux stack
468 selector = DefaultTrafficSelector.builder()
469 .matchInPort(phyPort)
470 .matchEthType(Ethernet.TYPE_ARP)
Hyunsun Moonaeb64212016-01-20 22:51:14 -0800471 .matchArpTpa(localIp.getIp4Address())
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800472 .build();
473
474 treatment = DefaultTrafficTreatment.builder()
475 .setOutput(PortNumber.LOCAL)
476 .build();
477
478 flowRule = DefaultFlowRule.builder()
479 .fromApp(appId)
480 .withSelector(selector)
481 .withTreatment(treatment)
482 .withPriority(HIGHER_PRIORITY)
483 .forDevice(deviceId)
484 .forTable(TABLE_FIRST)
485 .makePermanent()
486 .build();
487
488 processFlowRule(true, flowRule);
489
Hyunsun Moon4a915152016-01-14 16:56:26 -0800490 // take all else to the next table
491 selector = DefaultTrafficSelector.builder()
492 .build();
493
494 treatment = DefaultTrafficTreatment.builder()
495 .transition(TABLE_IN_PORT)
496 .build();
497
498 flowRule = DefaultFlowRule.builder()
499 .fromApp(appId)
500 .withSelector(selector)
501 .withTreatment(treatment)
502 .withPriority(LOWEST_PRIORITY)
503 .forDevice(deviceId)
504 .forTable(TABLE_FIRST)
505 .makePermanent()
506 .build();
507
508 processFlowRule(true, flowRule);
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800509 }
510
511 /**
Hyunsun Moon4a915152016-01-14 16:56:26 -0800512 * Forward table miss packets in ACCESS_TYPE table to physical port.
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800513 *
514 * @param deviceId device id
Hyunsun Moon4a915152016-01-14 16:56:26 -0800515 * @param phyPort physical port number
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800516 */
Hyunsun Moon4a915152016-01-14 16:56:26 -0800517 private void processAccessTypeTable(DeviceId deviceId, PortNumber phyPort) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800518 TrafficSelector selector = DefaultTrafficSelector.builder()
519 .build();
520
521 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Hyunsun Moon4a915152016-01-14 16:56:26 -0800522 .setOutput(phyPort)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800523 .build();
524
525 FlowRule flowRule = DefaultFlowRule.builder()
526 .fromApp(appId)
527 .withSelector(selector)
528 .withTreatment(treatment)
529 .withPriority(LOWEST_PRIORITY)
530 .forDevice(deviceId)
531 .forTable(TABLE_ACCESS_TYPE)
532 .makePermanent()
533 .build();
534
535 processFlowRule(true, flowRule);
536 }
537
538 /**
Hyunsun Moon4a915152016-01-14 16:56:26 -0800539 * Populates default rules for IN_PORT table.
540 * All packets from tunnel port are forwarded to TUNNEL_ID table and all packets
541 * from physical port to ACCESS_TYPE table.
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800542 *
543 * @param deviceId device id to install the rules
Hyunsun Moon4a915152016-01-14 16:56:26 -0800544 * @param tunnelPort tunnel port number
545 * @param phyPort physical port number
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800546 */
Hyunsun Moon4a915152016-01-14 16:56:26 -0800547 private void processInPortTable(DeviceId deviceId, PortNumber tunnelPort, PortNumber phyPort) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800548 checkNotNull(tunnelPort);
549
550 TrafficSelector selector = DefaultTrafficSelector.builder()
551 .matchInPort(tunnelPort)
552 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800553
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800554 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
555 .transition(TABLE_TUNNEL_IN)
556 .build();
557
558 FlowRule flowRule = DefaultFlowRule.builder()
559 .fromApp(appId)
560 .withSelector(selector)
561 .withTreatment(treatment)
562 .withPriority(DEFAULT_PRIORITY)
563 .forDevice(deviceId)
564 .forTable(TABLE_IN_PORT)
565 .makePermanent()
566 .build();
567
568 processFlowRule(true, flowRule);
Hyunsun Moon4a915152016-01-14 16:56:26 -0800569
570 selector = DefaultTrafficSelector.builder()
571 .matchInPort(phyPort)
572 .build();
573
574 treatment = DefaultTrafficTreatment.builder()
575 .transition(TABLE_DST_IP)
576 .build();
577
578 flowRule = DefaultFlowRule.builder()
579 .fromApp(appId)
580 .withSelector(selector)
581 .withTreatment(treatment)
582 .withPriority(DEFAULT_PRIORITY)
583 .forDevice(deviceId)
584 .forTable(TABLE_IN_PORT)
585 .makePermanent()
586 .build();
587
588 processFlowRule(true, flowRule);
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800589 }
590
591 /**
592 * Populates rules for local in port in IN_PORT table.
593 * Flows from a given in port, whose source IP is service IP transition
594 * to DST_TYPE table. Other flows transition to IN_SERVICE table.
595 *
596 * @param deviceId device id to install the rules
597 * @param inPort in port
598 * @param srcIp source ip
599 */
600 private void populateLocalInPortRule(DeviceId deviceId, PortNumber inPort, IpAddress srcIp) {
601 TrafficSelector selector = DefaultTrafficSelector.builder()
602 .matchInPort(inPort)
603 .matchEthType(Ethernet.TYPE_IPV4)
604 .matchIPSrc(srcIp.toIpPrefix())
605 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800606
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800607 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
608 .transition(TABLE_ACCESS_TYPE)
609 .build();
610
611
612 FlowRule flowRule = DefaultFlowRule.builder()
613 .fromApp(appId)
614 .withSelector(selector)
615 .withTreatment(treatment)
616 .withPriority(DEFAULT_PRIORITY)
617 .forDevice(deviceId)
618 .forTable(TABLE_IN_PORT)
619 .makePermanent()
620 .build();
621
622 processFlowRule(true, flowRule);
623
624 selector = DefaultTrafficSelector.builder()
625 .matchInPort(inPort)
626 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800627
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800628 treatment = DefaultTrafficTreatment.builder()
629 .transition(TABLE_IN_SERVICE)
630 .build();
631
632 flowRule = DefaultFlowRule.builder()
633 .fromApp(appId)
634 .withSelector(selector)
635 .withTreatment(treatment)
636 .withPriority(LOWER_PRIORITY)
637 .forDevice(deviceId)
638 .forTable(TABLE_IN_PORT)
639 .makePermanent()
640 .build();
641
642 processFlowRule(true, flowRule);
643 }
644
645 /**
646 * Populates direct VM access rules for ACCESS_TYPE table.
647 * These rules are installed to all devices.
648 *
649 * @param srcRange source ip range
650 * @param dstRange destination ip range
651 */
652 private void populateDirectAccessRule(Ip4Prefix srcRange, Ip4Prefix dstRange) {
653 TrafficSelector selector = DefaultTrafficSelector.builder()
654 .matchEthType(Ethernet.TYPE_IPV4)
655 .matchIPSrc(srcRange)
656 .matchIPDst(dstRange)
657 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800658
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800659 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
660 .transition(TABLE_DST_IP)
661 .build();
662
663 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
664 FlowRule flowRuleDirect = DefaultFlowRule.builder()
665 .fromApp(appId)
666 .withSelector(selector)
667 .withTreatment(treatment)
668 .withPriority(LOWER_PRIORITY)
669 .forDevice(device.id())
670 .forTable(TABLE_ACCESS_TYPE)
671 .makePermanent()
672 .build();
673
674 processFlowRule(true, flowRuleDirect);
675 }
676 }
677
678 /**
679 * Populates indirect service access rules for ACCESS_TYPE table.
680 * These rules are installed to all devices.
681 *
682 * @param srcRange source range
683 * @param serviceIp service ip
684 * @param outGroups list of output group
685 */
686 private void populateIndirectAccessRule(Ip4Prefix srcRange, Ip4Address serviceIp,
687 Map<DeviceId, GroupId> outGroups) {
688 TrafficSelector selector = DefaultTrafficSelector.builder()
689 .matchEthType(Ethernet.TYPE_IPV4)
690 .matchIPSrc(srcRange)
691 .matchIPDst(serviceIp.toIpPrefix())
692 .build();
693
694 for (Map.Entry<DeviceId, GroupId> outGroup : outGroups.entrySet()) {
695 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
696 .group(outGroup.getValue())
697 .build();
698
699 FlowRule flowRule = DefaultFlowRule.builder()
700 .fromApp(appId)
701 .withSelector(selector)
702 .withTreatment(treatment)
703 .withPriority(DEFAULT_PRIORITY)
704 .forDevice(outGroup.getKey())
705 .forTable(TABLE_ACCESS_TYPE)
706 .makePermanent()
707 .build();
708
709 processFlowRule(true, flowRule);
710 }
711 }
712
713 /**
714 * Populates flow rules for IN_SERVICE table.
715 *
716 * @param inPorts list of inports related to the service for each device
717 * @param outGroups set of output groups
718 */
719 private void populateInServiceRule(Map<DeviceId, Set<PortNumber>> inPorts, Map<DeviceId, GroupId> outGroups) {
720 checkNotNull(inPorts);
721 checkNotNull(outGroups);
722
723 for (Map.Entry<DeviceId, Set<PortNumber>> entry : inPorts.entrySet()) {
724 Set<PortNumber> ports = entry.getValue();
725 DeviceId deviceId = entry.getKey();
726
727 GroupId groupId = outGroups.get(deviceId);
728 if (groupId == null) {
729 continue;
730 }
731
732 ports.stream().forEach(port -> {
733 TrafficSelector selector = DefaultTrafficSelector.builder()
734 .matchInPort(port)
735 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800736
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800737 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
738 .group(groupId)
739 .build();
740
741 FlowRule flowRule = DefaultFlowRule.builder()
742 .fromApp(appId)
743 .withSelector(selector)
744 .withTreatment(treatment)
745 .withPriority(DEFAULT_PRIORITY)
746 .forDevice(deviceId)
747 .forTable(TABLE_IN_SERVICE)
748 .makePermanent()
749 .build();
750
751 processFlowRule(true, flowRule);
752 });
753 }
754 }
755
756 /**
757 * Populates flow rules for DST_IP table.
758 *
759 * @param deviceId device id
760 * @param inPort in port
761 * @param dstMac mac address
762 * @param dstIp destination ip
763 * @param tunnelId tunnel id
764 * @param tunnelIp tunnel remote ip
765 */
766 private void populateDstIpRule(DeviceId deviceId, PortNumber inPort, MacAddress dstMac,
767 IpAddress dstIp, long tunnelId, IpAddress tunnelIp) {
768 TrafficSelector selector = DefaultTrafficSelector.builder()
769 .matchEthType(Ethernet.TYPE_IPV4)
770 .matchIPDst(dstIp.toIpPrefix())
771 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800772
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800773 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
774 .setEthDst(dstMac)
775 .setOutput(inPort)
776 .build();
777
778 FlowRule flowRule = DefaultFlowRule.builder()
779 .fromApp(appId)
780 .withSelector(selector)
781 .withTreatment(treatment)
782 .withPriority(DEFAULT_PRIORITY)
783 .forDevice(deviceId)
784 .forTable(TABLE_DST_IP)
785 .makePermanent()
786 .build();
787
788 processFlowRule(true, flowRule);
789
790 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
791 if (device.id().equals(deviceId)) {
792 continue;
793 }
794
795 ExtensionTreatment tunnelDst = getTunnelDst(device.id(), tunnelIp.getIp4Address());
796 if (tunnelDst == null) {
797 continue;
798 }
799
800 treatment = DefaultTrafficTreatment.builder()
801 .setEthDst(dstMac)
802 .setTunnelId(tunnelId)
803 .extension(tunnelDst, device.id())
804 .setOutput(getTunnelPort(device.id()))
805 .build();
806
807 flowRule = DefaultFlowRule.builder()
808 .fromApp(appId)
809 .withSelector(selector)
810 .withTreatment(treatment)
811 .withPriority(DEFAULT_PRIORITY)
812 .forDevice(device.id())
813 .forTable(TABLE_DST_IP)
814 .makePermanent()
815 .build();
816
817 processFlowRule(true, flowRule);
818 }
819 }
820
821 /**
822 * Populates flow rules for TUNNEL_ID table.
823 *
824 * @param deviceId device id
825 * @param inPort in port
826 * @param mac mac address
827 * @param tunnelId tunnel id
828 */
829 private void populateTunnelInRule(DeviceId deviceId, PortNumber inPort, MacAddress mac, long tunnelId) {
830 TrafficSelector selector = DefaultTrafficSelector.builder()
831 .matchTunnelId(tunnelId)
832 .matchEthDst(mac)
833 .build();
834
835 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
836 .setOutput(inPort)
837 .build();
838
839 FlowRule flowRule = DefaultFlowRule.builder()
840 .fromApp(appId)
841 .withSelector(selector)
842 .withTreatment(treatment)
843 .withPriority(DEFAULT_PRIORITY)
844 .forDevice(deviceId)
845 .forTable(TABLE_TUNNEL_IN)
846 .makePermanent()
847 .build();
848
849 processFlowRule(true, flowRule);
850 }
851
852 /**
853 * Installs or uninstall a given rule.
854 *
855 * @param install true to install, false to uninstall
856 * @param rule rule
857 */
858 private void processFlowRule(boolean install, FlowRule rule) {
859 FlowRuleOperations.Builder oBuilder = FlowRuleOperations.builder();
860 oBuilder = install ? oBuilder.add(rule) : oBuilder.remove(rule);
861
862 flowRuleService.apply(oBuilder.build(new FlowRuleOperationsContext() {
863 @Override
864 public void onError(FlowRuleOperations ops) {
865 log.error(String.format("Failed %s, %s", ops.toString(), rule.toString()));
866 }
867 }));
868 }
869
870 /**
871 * Returns tunnel port of the device.
872 *
873 * @param deviceId device id
874 * @return tunnel port number, or null if no tunnel port exists on a given device
875 */
876 private PortNumber getTunnelPort(DeviceId deviceId) {
Hyunsun Moon5a4346f2016-01-15 11:41:14 -0800877 Port port = deviceService.getPorts(deviceId).stream()
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800878 .filter(p -> p.annotations().value("portName").contains(tunnelType))
Hyunsun Moon5a4346f2016-01-15 11:41:14 -0800879 .findFirst().orElse(null);
880
881 return port == null ? null : port.number();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800882 }
883
884 /**
Hyunsun Moon4a915152016-01-14 16:56:26 -0800885 * Returns physical port name of a given device.
886 *
887 * @param deviceId device id
888 * @param phyPortName physical port name
889 * @return physical port number, or null if no physical port exists
890 */
891 private PortNumber getPhyPort(DeviceId deviceId, String phyPortName) {
Hyunsun Moon5a4346f2016-01-15 11:41:14 -0800892 Port port = deviceService.getPorts(deviceId).stream()
Hyunsun Moon4a915152016-01-14 16:56:26 -0800893 .filter(p -> p.annotations().value("portName").contains(phyPortName) &&
894 p.isEnabled())
Hyunsun Moon5a4346f2016-01-15 11:41:14 -0800895 .findFirst().orElse(null);
896
897 return port == null ? null : port.number();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800898 }
899
900 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800901 * Returns the inport from a given flow rule if the rule contains the match of it.
902 *
903 * @param flowRule flow rule
904 * @return port number, or null if the rule doesn't have inport match
905 */
906 private PortNumber getInPort(FlowRule flowRule) {
907 Criterion criterion = flowRule.selector().getCriterion(IN_PORT);
908 if (criterion != null && criterion instanceof PortCriterion) {
909 PortCriterion port = (PortCriterion) criterion;
910 return port.port();
911 } else {
912 return null;
913 }
914 }
915
916 /**
917 * Returns the destination mac address from a given flow rule if the rule
918 * contains the instruction of it.
919 *
920 * @param flowRule flow rule
921 * @return mac address, or null if the rule doesn't have destination mac instruction
922 */
923 private MacAddress getDstMacFromTreatment(FlowRule flowRule) {
924 Instruction instruction = flowRule.treatment().allInstructions().stream()
925 .filter(inst -> inst instanceof ModEtherInstruction &&
926 ((ModEtherInstruction) inst).subtype().equals(ETH_DST))
927 .findFirst()
928 .orElse(null);
929
930 if (instruction == null) {
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800931 return null;
932 }
933
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800934 return ((ModEtherInstruction) instruction).mac();
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800935 }
936
937 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800938 * Returns the destination mac address from a given flow rule if the rule
939 * contains the match of it.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800940 *
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800941 * @param flowRule flow rule
942 * @return mac address, or null if the rule doesn't have destination mac match
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800943 */
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800944 private MacAddress getDstMacFromSelector(FlowRule flowRule) {
945 Criterion criterion = flowRule.selector().getCriterion(Criterion.Type.ETH_DST);
946 if (criterion != null && criterion instanceof EthCriterion) {
947 EthCriterion eth = (EthCriterion) criterion;
948 return eth.mac();
949 } else {
950 return null;
951 }
952 }
953
954 /**
955 * Returns the destination IP from a given flow rule if the rule contains
956 * the match of it.
957 *
958 * @param flowRule flow rule
959 * @return ip prefix, or null if the rule doesn't have ip match
960 */
961 private IpPrefix getDstIpFromSelector(FlowRule flowRule) {
962 Criterion criterion = flowRule.selector().getCriterion(IPV4_DST);
963 if (criterion != null && criterion instanceof IPCriterion) {
964 IPCriterion ip = (IPCriterion) criterion;
965 return ip.ip();
966 } else {
967 return null;
968 }
969 }
970
971 /**
972 * Returns the source IP from a given flow rule if the rule contains
973 * the match of it.
974 *
975 * @param flowRule flow rule
976 * @return ip prefix, or null if the rule doesn't have ip match
977 */
978 private IpPrefix getSrcIpFromSelector(FlowRule flowRule) {
979 Criterion criterion = flowRule.selector().getCriterion(IPV4_SRC);
980 if (criterion != null && criterion instanceof IPCriterion) {
981 IPCriterion ip = (IPCriterion) criterion;
982 return ip.ip();
983 } else {
984 return null;
985 }
986 }
987
988 /**
989 * Returns the group ID from a given flow rule if the rule contains the
990 * treatment of it.
991 *
992 * @param flowRule flow rule
993 * @return group id, or null if the rule doesn't have group instruction
994 */
995 private GroupId getGroupIdFromTreatment(FlowRule flowRule) {
996 Instruction instruction = flowRule.treatment().allInstructions().stream()
997 .filter(inst -> inst instanceof Instructions.GroupInstruction)
998 .findFirst()
999 .orElse(null);
1000
1001 if (instruction == null) {
1002 return null;
1003 }
1004
1005 return ((Instructions.GroupInstruction) instruction).groupId();
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001006 }
1007
1008 /**
Hyunsun Moon4a915152016-01-14 16:56:26 -08001009 * Creates a new group for a given service.
1010 *
1011 * @param deviceId device id to create a group
1012 * @param service cord service
1013 * @return group id, or null if it fails to create
1014 */
1015 private GroupId createServiceGroup(DeviceId deviceId, CordService service) {
1016 checkNotNull(service);
1017
1018 GroupKey groupKey = getGroupKey(service.id());
1019 Group group = groupService.getGroup(deviceId, groupKey);
1020 GroupId groupId = getGroupId(service.id(), deviceId);
1021
1022 if (group != null) {
1023 log.debug("Group {} is already exist in {}", service.id(), deviceId);
1024 return groupId;
1025 }
1026
1027 GroupBuckets buckets = getServiceGroupBuckets(deviceId, service.segmentationId(), service.hosts());
1028 GroupDescription groupDescription = new DefaultGroupDescription(
1029 deviceId,
1030 GroupDescription.Type.SELECT,
1031 buckets,
1032 groupKey,
1033 groupId.id(),
1034 appId);
1035
1036 groupService.addGroup(groupDescription);
1037
1038 return groupId;
1039 }
1040
1041 /**
1042 * Returns group buckets for a given device.
1043 *
1044 * @param deviceId device id
1045 * @param tunnelId tunnel id
1046 * @param hosts list of host
1047 * @return group buckets
1048 */
1049 private GroupBuckets getServiceGroupBuckets(DeviceId deviceId, long tunnelId, Map<Host, IpAddress> hosts) {
1050 List<GroupBucket> buckets = Lists.newArrayList();
1051
1052 for (Map.Entry<Host, IpAddress> entry : hosts.entrySet()) {
1053 Host host = entry.getKey();
1054 Ip4Address remoteIp = entry.getValue().getIp4Address();
1055 DeviceId hostDevice = host.location().deviceId();
1056
1057 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
1058 .builder()
1059 .setEthDst(host.mac());
1060
1061 if (deviceId.equals(hostDevice)) {
1062 tBuilder.setOutput(host.location().port());
1063 } else {
1064 ExtensionTreatment tunnelDst = getTunnelDst(deviceId, remoteIp);
1065 if (tunnelDst == null) {
1066 continue;
1067 }
1068
1069 tBuilder.extension(tunnelDst, deviceId)
1070 .setTunnelId(tunnelId)
1071 .setOutput(getTunnelPort(hostDevice));
1072 }
1073
1074 buckets.add(DefaultGroupBucket.createSelectGroupBucket(tBuilder.build()));
1075 }
1076
1077 return new GroupBuckets(buckets);
1078 }
1079
1080 /**
1081 * Returns globally unique group ID.
1082 *
1083 * @param serviceId service id
1084 * @param deviceId device id
1085 * @return group id
1086 */
1087 private GroupId getGroupId(CordServiceId serviceId, DeviceId deviceId) {
1088 return new DefaultGroupId(Objects.hash(serviceId, deviceId));
1089 }
1090
1091 /**
1092 * Returns group key of a service.
1093 *
1094 * @param serviceId service id
1095 * @return group key
1096 */
1097 private GroupKey getGroupKey(CordServiceId serviceId) {
1098 return new DefaultGroupKey(serviceId.id().getBytes());
1099 }
1100
1101 /**
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001102 * Returns extension instruction to set tunnel destination.
1103 *
1104 * @param deviceId device id
1105 * @param remoteIp tunnel destination address
1106 * @return extension treatment or null if it fails to get instruction
1107 */
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001108 private ExtensionTreatment getTunnelDst(DeviceId deviceId, Ip4Address remoteIp) {
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001109 try {
1110 Driver driver = driverService.getDriver(deviceId);
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001111 DefaultDriverData driverData = new DefaultDriverData(driver, deviceId);
1112 DriverHandler handler = new DefaultDriverHandler(driverData);
1113 ExtensionTreatmentResolver resolver = handler.behaviour(ExtensionTreatmentResolver.class);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001114
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001115 ExtensionTreatment treatment =
1116 resolver.getExtensionInstruction(NICIRA_SET_TUNNEL_DST.type());
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001117 treatment.setPropertyValue("tunnelDst", remoteIp);
1118
1119 return treatment;
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001120 } catch (ItemNotFoundException | UnsupportedOperationException |
1121 ExtensionPropertyException e) {
1122 log.error("Failed to get extension instruction {}", deviceId);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001123 return null;
1124 }
1125 }
1126}
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001127