blob: d9b29bd9ef505d0fc63a227b6995cebb4c477fce [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
128 * @param tunnelType tunnel type
129 */
130 public CordVtnRuleInstaller(ApplicationId appId,
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800131 FlowRuleService flowRuleService,
132 DeviceService deviceService,
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800133 DriverService driverService,
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800134 GroupService groupService,
135 MastershipService mastershipService,
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800136 String tunnelType) {
137 this.appId = appId;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800138 this.flowRuleService = flowRuleService;
139 this.deviceService = deviceService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800140 this.driverService = driverService;
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800141 this.groupService = groupService;
142 this.mastershipService = mastershipService;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800143 this.tunnelType = checkNotNull(tunnelType);
144 }
145
146 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800147 * Installs table miss rule to a give device.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800148 *
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800149 * @param deviceId device id to install the rules
Hyunsun Moon4a915152016-01-14 16:56:26 -0800150 * @param phyPortName physical port name
151 * @param localIp local data plane ip address
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800152 */
Hyunsun Moon4a915152016-01-14 16:56:26 -0800153 public void init(DeviceId deviceId, String phyPortName, IpAddress localIp) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800154 // default is drop packets which can be accomplished without
155 // a table miss entry for all table.
Hyunsun Moon4a915152016-01-14 16:56:26 -0800156 PortNumber tunnelPort = getTunnelPort(deviceId);
157 PortNumber phyPort = getPhyPort(deviceId, phyPortName);
158
159 processFirstTable(deviceId, phyPort, localIp);
160 processInPortTable(deviceId, tunnelPort, phyPort);
161 processAccessTypeTable(deviceId, phyPort);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800162 }
163
164 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800165 * Populates basic rules that connect a VM to the other VMs in the system.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800166 *
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800167 * @param host host
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800168 * @param tunnelIp tunnel ip
169 * @param vNet openstack network
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800170 */
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800171 public void populateBasicConnectionRules(Host host, IpAddress tunnelIp, OpenstackNetwork vNet) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800172 checkNotNull(host);
173 checkNotNull(vNet);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800174
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800175 DeviceId deviceId = host.location().deviceId();
176 if (!mastershipService.isLocalMaster(deviceId)) {
177 return;
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800178 }
179
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800180 PortNumber inPort = host.location().port();
181 MacAddress dstMac = host.mac();
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800182 IpAddress hostIp = host.ipAddresses().stream().findFirst().get();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800183 long tunnelId = Long.parseLong(vNet.segmentId());
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800184
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800185 OpenstackSubnet subnet = vNet.subnets().stream()
186 .findFirst()
187 .orElse(null);
188
189 if (subnet == null) {
190 log.error("Failed to get subnet for {}", host.id());
191 return;
192 }
193
194 populateLocalInPortRule(deviceId, inPort, hostIp);
195 populateDirectAccessRule(Ip4Prefix.valueOf(subnet.cidr()), Ip4Prefix.valueOf(subnet.cidr()));
196 populateDstIpRule(deviceId, inPort, dstMac, hostIp, tunnelId, tunnelIp);
197 populateTunnelInRule(deviceId, inPort, dstMac, tunnelId);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800198 }
199
200 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800201 * Removes basic rules related to a given flow information.
202 *
203 * @param host host to be removed
204 */
205 public void removeBasicConnectionRules(Host host) {
206 checkNotNull(host);
207
208 DeviceId deviceId = host.location().deviceId();
209 MacAddress mac = host.mac();
210 PortNumber port = host.location().port();
211 IpAddress ip = host.ipAddresses().stream().findFirst().orElse(null);
212
213 if (!mastershipService.isLocalMaster(deviceId)) {
214 return;
215 }
216
217 for (FlowRule flowRule : flowRuleService.getFlowRulesById(appId)) {
218 if (flowRule.deviceId().equals(deviceId)) {
219 PortNumber inPort = getInPort(flowRule);
220 if (inPort != null && inPort.equals(port)) {
221 processFlowRule(false, flowRule);
222 continue;
223 }
224 }
225
226 MacAddress dstMac = getDstMacFromTreatment(flowRule);
227 if (dstMac != null && dstMac.equals(mac)) {
228 processFlowRule(false, flowRule);
229 continue;
230 }
231
232 dstMac = getDstMacFromSelector(flowRule);
233 if (dstMac != null && dstMac.equals(mac)) {
234 processFlowRule(false, flowRule);
235 continue;
236 }
237
238 IpPrefix dstIp = getDstIpFromSelector(flowRule);
239 if (dstIp != null && dstIp.equals(ip.toIpPrefix())) {
240 processFlowRule(false, flowRule);
241 }
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800242 }
243
244 // TODO uninstall same network access rule in access table if no vm exists in the network
245 }
246
247 /**
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800248 * Populates service dependency rules.
249 *
250 * @param tService tenant cord service
251 * @param pService provider cord service
252 */
253 public void populateServiceDependencyRules(CordService tService, CordService pService) {
254 checkNotNull(tService);
255 checkNotNull(pService);
256
257 Ip4Prefix srcRange = tService.serviceIpRange().getIp4Prefix();
258 Ip4Prefix dstRange = pService.serviceIpRange().getIp4Prefix();
259 Ip4Address serviceIp = pService.serviceIp().getIp4Address();
260
261 Map<DeviceId, GroupId> outGroups = Maps.newHashMap();
262 Map<DeviceId, Set<PortNumber>> inPorts = Maps.newHashMap();
263
264 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
265 GroupId groupId = createServiceGroup(device.id(), pService);
266 outGroups.put(device.id(), groupId);
267
268 Set<PortNumber> vms = tService.hosts().keySet()
269 .stream()
270 .filter(host -> host.location().deviceId().equals(device.id()))
271 .map(host -> host.location().port())
272 .collect(Collectors.toSet());
273 inPorts.put(device.id(), vms);
274 }
275
276 populateIndirectAccessRule(srcRange, serviceIp, outGroups);
277 populateDirectAccessRule(srcRange, dstRange);
278 populateInServiceRule(inPorts, outGroups);
279 }
280
281 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800282 * Removes service dependency rules.
283 *
284 * @param tService tenant cord service
285 * @param pService provider cord service
286 */
287 public void removeServiceDependencyRules(CordService tService, CordService pService) {
288 checkNotNull(tService);
289 checkNotNull(pService);
290
291 Ip4Prefix srcRange = tService.serviceIpRange().getIp4Prefix();
292 Ip4Prefix dstRange = pService.serviceIpRange().getIp4Prefix();
293 IpPrefix serviceIp = pService.serviceIp().toIpPrefix();
294
295 Map<DeviceId, GroupId> outGroups = Maps.newHashMap();
296 GroupKey groupKey = new DefaultGroupKey(pService.id().id().getBytes());
297
298 deviceService.getAvailableDevices(SWITCH).forEach(device -> {
299 Group group = groupService.getGroup(device.id(), groupKey);
300 if (group != null) {
301 outGroups.put(device.id(), group.id());
302 }
303 });
304
305 for (FlowRule flowRule : flowRuleService.getFlowRulesById(appId)) {
306 IpPrefix dstIp = getDstIpFromSelector(flowRule);
307 IpPrefix srcIp = getSrcIpFromSelector(flowRule);
308
309 if (dstIp != null && dstIp.equals(serviceIp)) {
310 processFlowRule(false, flowRule);
311 continue;
312 }
313
314 if (dstIp != null && srcIp != null) {
315 if (dstIp.equals(dstRange) && srcIp.equals(srcRange)) {
316 processFlowRule(false, flowRule);
317 continue;
318 }
319
320 if (dstIp.equals(srcRange) && srcIp.equals(dstRange)) {
321 processFlowRule(false, flowRule);
322 continue;
323 }
324 }
325
326 GroupId groupId = getGroupIdFromTreatment(flowRule);
327 if (groupId != null && groupId.equals(outGroups.get(flowRule.deviceId()))) {
328 processFlowRule(false, flowRule);
329 }
330 }
331
332 // TODO remove the group if it is not in use
333 }
334
335 /**
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800336 * Updates group buckets for a given service to all devices.
337 *
338 * @param service cord service
339 */
340 public void updateServiceGroup(CordService service) {
341 checkNotNull(service);
342
343 GroupKey groupKey = getGroupKey(service.id());
344
345 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
346 DeviceId deviceId = device.id();
347 if (!mastershipService.isLocalMaster(deviceId)) {
348 continue;
349 }
350
351 Group group = groupService.getGroup(deviceId, groupKey);
352 if (group == null) {
Hyunsun Moonb77b60f2016-01-15 20:03:18 -0800353 log.trace("No group exists for service {} in {}, do nothing.", service.id(), deviceId);
Hyunsun Moon4161e6f2016-01-07 01:32:31 -0800354 continue;
355 }
356
357 List<GroupBucket> oldBuckets = group.buckets().buckets();
358 List<GroupBucket> newBuckets = getServiceGroupBuckets(
359 deviceId, service.segmentationId(), service.hosts()).buckets();
360
361 if (oldBuckets.equals(newBuckets)) {
362 continue;
363 }
364
365 List<GroupBucket> bucketsToRemove = new ArrayList<>(oldBuckets);
366 bucketsToRemove.removeAll(newBuckets);
367 if (!bucketsToRemove.isEmpty()) {
368 groupService.removeBucketsFromGroup(
369 deviceId,
370 groupKey,
371 new GroupBuckets(bucketsToRemove),
372 groupKey, appId);
373 }
374
375 List<GroupBucket> bucketsToAdd = new ArrayList<>(newBuckets);
376 bucketsToAdd.removeAll(oldBuckets);
377 if (!bucketsToAdd.isEmpty()) {
378 groupService.addBucketsToGroup(
379 deviceId,
380 groupKey,
381 new GroupBuckets(bucketsToAdd),
382 groupKey, appId);
383 }
384 }
385 }
386
387 /**
Hyunsun Moon4a915152016-01-14 16:56:26 -0800388 * Populates default rules on the first table.
389 * The rules are for shuttling vxlan-encapped packets and supporting physical
390 * network connectivity.
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800391 *
392 * @param deviceId device id
Hyunsun Moon4a915152016-01-14 16:56:26 -0800393 * @param phyPort physical port number
394 * @param localIp local data plane ip address
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800395 */
Hyunsun Moon4a915152016-01-14 16:56:26 -0800396 private void processFirstTable(DeviceId deviceId, PortNumber phyPort, IpAddress localIp) {
397 // take vxlan packet out onto the physical port
398 TrafficSelector selector = DefaultTrafficSelector.builder()
399 .matchInPort(PortNumber.LOCAL)
400 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800401
Hyunsun Moon4a915152016-01-14 16:56:26 -0800402 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
403 .setOutput(phyPort)
404 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800405
Hyunsun Moon4a915152016-01-14 16:56:26 -0800406 FlowRule flowRule = DefaultFlowRule.builder()
407 .fromApp(appId)
408 .withSelector(selector)
409 .withTreatment(treatment)
410 .withPriority(HIGHER_PRIORITY)
411 .forDevice(deviceId)
412 .forTable(TABLE_FIRST)
413 .makePermanent()
414 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800415
Hyunsun Moon4a915152016-01-14 16:56:26 -0800416 processFlowRule(true, flowRule);
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800417
Hyunsun Moon4a915152016-01-14 16:56:26 -0800418 // take a vxlan encap'd packet through the Linux stack
419 selector = DefaultTrafficSelector.builder()
420 .matchInPort(phyPort)
421 .matchEthType(Ethernet.TYPE_IPV4)
422 .matchIPProtocol(IPv4.PROTOCOL_UDP)
423 .matchUdpDst(TpPort.tpPort(VXLAN_UDP_PORT))
424 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800425
Hyunsun Moon4a915152016-01-14 16:56:26 -0800426 treatment = DefaultTrafficTreatment.builder()
427 .setOutput(PortNumber.LOCAL)
428 .build();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800429
Hyunsun Moon4a915152016-01-14 16:56:26 -0800430 flowRule = DefaultFlowRule.builder()
431 .fromApp(appId)
432 .withSelector(selector)
433 .withTreatment(treatment)
434 .withPriority(HIGHER_PRIORITY)
435 .forDevice(deviceId)
436 .forTable(TABLE_FIRST)
437 .makePermanent()
438 .build();
439
440 processFlowRule(true, flowRule);
441
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800442 // take a packet to the local ip through Linux stack
443 selector = DefaultTrafficSelector.builder()
444 .matchInPort(phyPort)
445 .matchEthType(Ethernet.TYPE_IPV4)
446 .matchIPDst(localIp.toIpPrefix())
447 .build();
448
449 treatment = DefaultTrafficTreatment.builder()
450 .setOutput(PortNumber.LOCAL)
451 .build();
452
453 flowRule = DefaultFlowRule.builder()
454 .fromApp(appId)
455 .withSelector(selector)
456 .withTreatment(treatment)
457 .withPriority(HIGHER_PRIORITY)
458 .forDevice(deviceId)
459 .forTable(TABLE_FIRST)
460 .makePermanent()
461 .build();
462
463 processFlowRule(true, flowRule);
464
465 // take an arp packet from physical through Linux stack
466 selector = DefaultTrafficSelector.builder()
467 .matchInPort(phyPort)
468 .matchEthType(Ethernet.TYPE_ARP)
Hyunsun Moonaeb64212016-01-20 22:51:14 -0800469 .matchArpTpa(localIp.getIp4Address())
Hyunsun Moonb4f85082016-01-15 20:11:41 -0800470 .build();
471
472 treatment = DefaultTrafficTreatment.builder()
473 .setOutput(PortNumber.LOCAL)
474 .build();
475
476 flowRule = DefaultFlowRule.builder()
477 .fromApp(appId)
478 .withSelector(selector)
479 .withTreatment(treatment)
480 .withPriority(HIGHER_PRIORITY)
481 .forDevice(deviceId)
482 .forTable(TABLE_FIRST)
483 .makePermanent()
484 .build();
485
486 processFlowRule(true, flowRule);
487
Hyunsun Moon4a915152016-01-14 16:56:26 -0800488 // take all else to the next table
489 selector = DefaultTrafficSelector.builder()
490 .build();
491
492 treatment = DefaultTrafficTreatment.builder()
493 .transition(TABLE_IN_PORT)
494 .build();
495
496 flowRule = DefaultFlowRule.builder()
497 .fromApp(appId)
498 .withSelector(selector)
499 .withTreatment(treatment)
500 .withPriority(LOWEST_PRIORITY)
501 .forDevice(deviceId)
502 .forTable(TABLE_FIRST)
503 .makePermanent()
504 .build();
505
506 processFlowRule(true, flowRule);
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800507 }
508
509 /**
Hyunsun Moon4a915152016-01-14 16:56:26 -0800510 * Forward table miss packets in ACCESS_TYPE table to physical port.
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800511 *
512 * @param deviceId device id
Hyunsun Moon4a915152016-01-14 16:56:26 -0800513 * @param phyPort physical port number
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800514 */
Hyunsun Moon4a915152016-01-14 16:56:26 -0800515 private void processAccessTypeTable(DeviceId deviceId, PortNumber phyPort) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800516 TrafficSelector selector = DefaultTrafficSelector.builder()
517 .build();
518
519 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Hyunsun Moon4a915152016-01-14 16:56:26 -0800520 .setOutput(phyPort)
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800521 .build();
522
523 FlowRule flowRule = DefaultFlowRule.builder()
524 .fromApp(appId)
525 .withSelector(selector)
526 .withTreatment(treatment)
527 .withPriority(LOWEST_PRIORITY)
528 .forDevice(deviceId)
529 .forTable(TABLE_ACCESS_TYPE)
530 .makePermanent()
531 .build();
532
533 processFlowRule(true, flowRule);
534 }
535
536 /**
Hyunsun Moon4a915152016-01-14 16:56:26 -0800537 * Populates default rules for IN_PORT table.
538 * All packets from tunnel port are forwarded to TUNNEL_ID table and all packets
539 * from physical port to ACCESS_TYPE table.
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800540 *
541 * @param deviceId device id to install the rules
Hyunsun Moon4a915152016-01-14 16:56:26 -0800542 * @param tunnelPort tunnel port number
543 * @param phyPort physical port number
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800544 */
Hyunsun Moon4a915152016-01-14 16:56:26 -0800545 private void processInPortTable(DeviceId deviceId, PortNumber tunnelPort, PortNumber phyPort) {
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800546 checkNotNull(tunnelPort);
547
548 TrafficSelector selector = DefaultTrafficSelector.builder()
549 .matchInPort(tunnelPort)
550 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800551
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800552 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
553 .transition(TABLE_TUNNEL_IN)
554 .build();
555
556 FlowRule flowRule = DefaultFlowRule.builder()
557 .fromApp(appId)
558 .withSelector(selector)
559 .withTreatment(treatment)
560 .withPriority(DEFAULT_PRIORITY)
561 .forDevice(deviceId)
562 .forTable(TABLE_IN_PORT)
563 .makePermanent()
564 .build();
565
566 processFlowRule(true, flowRule);
Hyunsun Moon4a915152016-01-14 16:56:26 -0800567
568 selector = DefaultTrafficSelector.builder()
569 .matchInPort(phyPort)
570 .build();
571
572 treatment = DefaultTrafficTreatment.builder()
573 .transition(TABLE_DST_IP)
574 .build();
575
576 flowRule = DefaultFlowRule.builder()
577 .fromApp(appId)
578 .withSelector(selector)
579 .withTreatment(treatment)
580 .withPriority(DEFAULT_PRIORITY)
581 .forDevice(deviceId)
582 .forTable(TABLE_IN_PORT)
583 .makePermanent()
584 .build();
585
586 processFlowRule(true, flowRule);
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800587 }
588
589 /**
590 * Populates rules for local in port in IN_PORT table.
591 * Flows from a given in port, whose source IP is service IP transition
592 * to DST_TYPE table. Other flows transition to IN_SERVICE table.
593 *
594 * @param deviceId device id to install the rules
595 * @param inPort in port
596 * @param srcIp source ip
597 */
598 private void populateLocalInPortRule(DeviceId deviceId, PortNumber inPort, IpAddress srcIp) {
599 TrafficSelector selector = DefaultTrafficSelector.builder()
600 .matchInPort(inPort)
601 .matchEthType(Ethernet.TYPE_IPV4)
602 .matchIPSrc(srcIp.toIpPrefix())
603 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800604
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800605 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
606 .transition(TABLE_ACCESS_TYPE)
607 .build();
608
609
610 FlowRule flowRule = DefaultFlowRule.builder()
611 .fromApp(appId)
612 .withSelector(selector)
613 .withTreatment(treatment)
614 .withPriority(DEFAULT_PRIORITY)
615 .forDevice(deviceId)
616 .forTable(TABLE_IN_PORT)
617 .makePermanent()
618 .build();
619
620 processFlowRule(true, flowRule);
621
622 selector = DefaultTrafficSelector.builder()
623 .matchInPort(inPort)
624 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800625
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800626 treatment = DefaultTrafficTreatment.builder()
627 .transition(TABLE_IN_SERVICE)
628 .build();
629
630 flowRule = DefaultFlowRule.builder()
631 .fromApp(appId)
632 .withSelector(selector)
633 .withTreatment(treatment)
634 .withPriority(LOWER_PRIORITY)
635 .forDevice(deviceId)
636 .forTable(TABLE_IN_PORT)
637 .makePermanent()
638 .build();
639
640 processFlowRule(true, flowRule);
641 }
642
643 /**
644 * Populates direct VM access rules for ACCESS_TYPE table.
645 * These rules are installed to all devices.
646 *
647 * @param srcRange source ip range
648 * @param dstRange destination ip range
649 */
650 private void populateDirectAccessRule(Ip4Prefix srcRange, Ip4Prefix dstRange) {
651 TrafficSelector selector = DefaultTrafficSelector.builder()
652 .matchEthType(Ethernet.TYPE_IPV4)
653 .matchIPSrc(srcRange)
654 .matchIPDst(dstRange)
655 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800656
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800657 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
658 .transition(TABLE_DST_IP)
659 .build();
660
661 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
662 FlowRule flowRuleDirect = DefaultFlowRule.builder()
663 .fromApp(appId)
664 .withSelector(selector)
665 .withTreatment(treatment)
666 .withPriority(LOWER_PRIORITY)
667 .forDevice(device.id())
668 .forTable(TABLE_ACCESS_TYPE)
669 .makePermanent()
670 .build();
671
672 processFlowRule(true, flowRuleDirect);
673 }
674 }
675
676 /**
677 * Populates indirect service access rules for ACCESS_TYPE table.
678 * These rules are installed to all devices.
679 *
680 * @param srcRange source range
681 * @param serviceIp service ip
682 * @param outGroups list of output group
683 */
684 private void populateIndirectAccessRule(Ip4Prefix srcRange, Ip4Address serviceIp,
685 Map<DeviceId, GroupId> outGroups) {
686 TrafficSelector selector = DefaultTrafficSelector.builder()
687 .matchEthType(Ethernet.TYPE_IPV4)
688 .matchIPSrc(srcRange)
689 .matchIPDst(serviceIp.toIpPrefix())
690 .build();
691
692 for (Map.Entry<DeviceId, GroupId> outGroup : outGroups.entrySet()) {
693 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
694 .group(outGroup.getValue())
695 .build();
696
697 FlowRule flowRule = DefaultFlowRule.builder()
698 .fromApp(appId)
699 .withSelector(selector)
700 .withTreatment(treatment)
701 .withPriority(DEFAULT_PRIORITY)
702 .forDevice(outGroup.getKey())
703 .forTable(TABLE_ACCESS_TYPE)
704 .makePermanent()
705 .build();
706
707 processFlowRule(true, flowRule);
708 }
709 }
710
711 /**
712 * Populates flow rules for IN_SERVICE table.
713 *
714 * @param inPorts list of inports related to the service for each device
715 * @param outGroups set of output groups
716 */
717 private void populateInServiceRule(Map<DeviceId, Set<PortNumber>> inPorts, Map<DeviceId, GroupId> outGroups) {
718 checkNotNull(inPorts);
719 checkNotNull(outGroups);
720
721 for (Map.Entry<DeviceId, Set<PortNumber>> entry : inPorts.entrySet()) {
722 Set<PortNumber> ports = entry.getValue();
723 DeviceId deviceId = entry.getKey();
724
725 GroupId groupId = outGroups.get(deviceId);
726 if (groupId == null) {
727 continue;
728 }
729
730 ports.stream().forEach(port -> {
731 TrafficSelector selector = DefaultTrafficSelector.builder()
732 .matchInPort(port)
733 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800734
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800735 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
736 .group(groupId)
737 .build();
738
739 FlowRule flowRule = DefaultFlowRule.builder()
740 .fromApp(appId)
741 .withSelector(selector)
742 .withTreatment(treatment)
743 .withPriority(DEFAULT_PRIORITY)
744 .forDevice(deviceId)
745 .forTable(TABLE_IN_SERVICE)
746 .makePermanent()
747 .build();
748
749 processFlowRule(true, flowRule);
750 });
751 }
752 }
753
754 /**
755 * Populates flow rules for DST_IP table.
756 *
757 * @param deviceId device id
758 * @param inPort in port
759 * @param dstMac mac address
760 * @param dstIp destination ip
761 * @param tunnelId tunnel id
762 * @param tunnelIp tunnel remote ip
763 */
764 private void populateDstIpRule(DeviceId deviceId, PortNumber inPort, MacAddress dstMac,
765 IpAddress dstIp, long tunnelId, IpAddress tunnelIp) {
766 TrafficSelector selector = DefaultTrafficSelector.builder()
767 .matchEthType(Ethernet.TYPE_IPV4)
768 .matchIPDst(dstIp.toIpPrefix())
769 .build();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800770
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800771 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
772 .setEthDst(dstMac)
773 .setOutput(inPort)
774 .build();
775
776 FlowRule flowRule = DefaultFlowRule.builder()
777 .fromApp(appId)
778 .withSelector(selector)
779 .withTreatment(treatment)
780 .withPriority(DEFAULT_PRIORITY)
781 .forDevice(deviceId)
782 .forTable(TABLE_DST_IP)
783 .makePermanent()
784 .build();
785
786 processFlowRule(true, flowRule);
787
788 for (Device device : deviceService.getAvailableDevices(SWITCH)) {
789 if (device.id().equals(deviceId)) {
790 continue;
791 }
792
793 ExtensionTreatment tunnelDst = getTunnelDst(device.id(), tunnelIp.getIp4Address());
794 if (tunnelDst == null) {
795 continue;
796 }
797
798 treatment = DefaultTrafficTreatment.builder()
799 .setEthDst(dstMac)
800 .setTunnelId(tunnelId)
801 .extension(tunnelDst, device.id())
802 .setOutput(getTunnelPort(device.id()))
803 .build();
804
805 flowRule = DefaultFlowRule.builder()
806 .fromApp(appId)
807 .withSelector(selector)
808 .withTreatment(treatment)
809 .withPriority(DEFAULT_PRIORITY)
810 .forDevice(device.id())
811 .forTable(TABLE_DST_IP)
812 .makePermanent()
813 .build();
814
815 processFlowRule(true, flowRule);
816 }
817 }
818
819 /**
820 * Populates flow rules for TUNNEL_ID table.
821 *
822 * @param deviceId device id
823 * @param inPort in port
824 * @param mac mac address
825 * @param tunnelId tunnel id
826 */
827 private void populateTunnelInRule(DeviceId deviceId, PortNumber inPort, MacAddress mac, long tunnelId) {
828 TrafficSelector selector = DefaultTrafficSelector.builder()
829 .matchTunnelId(tunnelId)
830 .matchEthDst(mac)
831 .build();
832
833 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
834 .setOutput(inPort)
835 .build();
836
837 FlowRule flowRule = DefaultFlowRule.builder()
838 .fromApp(appId)
839 .withSelector(selector)
840 .withTreatment(treatment)
841 .withPriority(DEFAULT_PRIORITY)
842 .forDevice(deviceId)
843 .forTable(TABLE_TUNNEL_IN)
844 .makePermanent()
845 .build();
846
847 processFlowRule(true, flowRule);
848 }
849
850 /**
851 * Installs or uninstall a given rule.
852 *
853 * @param install true to install, false to uninstall
854 * @param rule rule
855 */
856 private void processFlowRule(boolean install, FlowRule rule) {
857 FlowRuleOperations.Builder oBuilder = FlowRuleOperations.builder();
858 oBuilder = install ? oBuilder.add(rule) : oBuilder.remove(rule);
859
860 flowRuleService.apply(oBuilder.build(new FlowRuleOperationsContext() {
861 @Override
862 public void onError(FlowRuleOperations ops) {
863 log.error(String.format("Failed %s, %s", ops.toString(), rule.toString()));
864 }
865 }));
866 }
867
868 /**
869 * Returns tunnel port of the device.
870 *
871 * @param deviceId device id
872 * @return tunnel port number, or null if no tunnel port exists on a given device
873 */
874 private PortNumber getTunnelPort(DeviceId deviceId) {
Hyunsun Moon5a4346f2016-01-15 11:41:14 -0800875 Port port = deviceService.getPorts(deviceId).stream()
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800876 .filter(p -> p.annotations().value("portName").contains(tunnelType))
Hyunsun Moon5a4346f2016-01-15 11:41:14 -0800877 .findFirst().orElse(null);
878
879 return port == null ? null : port.number();
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800880 }
881
882 /**
Hyunsun Moon4a915152016-01-14 16:56:26 -0800883 * Returns physical port name of a given device.
884 *
885 * @param deviceId device id
886 * @param phyPortName physical port name
887 * @return physical port number, or null if no physical port exists
888 */
889 private PortNumber getPhyPort(DeviceId deviceId, String phyPortName) {
Hyunsun Moon5a4346f2016-01-15 11:41:14 -0800890 Port port = deviceService.getPorts(deviceId).stream()
Hyunsun Moon4a915152016-01-14 16:56:26 -0800891 .filter(p -> p.annotations().value("portName").contains(phyPortName) &&
892 p.isEnabled())
Hyunsun Moon5a4346f2016-01-15 11:41:14 -0800893 .findFirst().orElse(null);
894
895 return port == null ? null : port.number();
Hyunsun Moon4a915152016-01-14 16:56:26 -0800896 }
897
898 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800899 * Returns the inport from a given flow rule if the rule contains the match of it.
900 *
901 * @param flowRule flow rule
902 * @return port number, or null if the rule doesn't have inport match
903 */
904 private PortNumber getInPort(FlowRule flowRule) {
905 Criterion criterion = flowRule.selector().getCriterion(IN_PORT);
906 if (criterion != null && criterion instanceof PortCriterion) {
907 PortCriterion port = (PortCriterion) criterion;
908 return port.port();
909 } else {
910 return null;
911 }
912 }
913
914 /**
915 * Returns the destination mac address from a given flow rule if the rule
916 * contains the instruction of it.
917 *
918 * @param flowRule flow rule
919 * @return mac address, or null if the rule doesn't have destination mac instruction
920 */
921 private MacAddress getDstMacFromTreatment(FlowRule flowRule) {
922 Instruction instruction = flowRule.treatment().allInstructions().stream()
923 .filter(inst -> inst instanceof ModEtherInstruction &&
924 ((ModEtherInstruction) inst).subtype().equals(ETH_DST))
925 .findFirst()
926 .orElse(null);
927
928 if (instruction == null) {
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800929 return null;
930 }
931
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800932 return ((ModEtherInstruction) instruction).mac();
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800933 }
934
935 /**
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800936 * Returns the destination mac address from a given flow rule if the rule
937 * contains the match of it.
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800938 *
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800939 * @param flowRule flow rule
940 * @return mac address, or null if the rule doesn't have destination mac match
Hyunsun Moon9f0814b2015-11-04 17:34:35 -0800941 */
Hyunsun Moonc71231d2015-12-16 20:53:23 -0800942 private MacAddress getDstMacFromSelector(FlowRule flowRule) {
943 Criterion criterion = flowRule.selector().getCriterion(Criterion.Type.ETH_DST);
944 if (criterion != null && criterion instanceof EthCriterion) {
945 EthCriterion eth = (EthCriterion) criterion;
946 return eth.mac();
947 } else {
948 return null;
949 }
950 }
951
952 /**
953 * Returns the destination IP from a given flow rule if the rule contains
954 * the match of it.
955 *
956 * @param flowRule flow rule
957 * @return ip prefix, or null if the rule doesn't have ip match
958 */
959 private IpPrefix getDstIpFromSelector(FlowRule flowRule) {
960 Criterion criterion = flowRule.selector().getCriterion(IPV4_DST);
961 if (criterion != null && criterion instanceof IPCriterion) {
962 IPCriterion ip = (IPCriterion) criterion;
963 return ip.ip();
964 } else {
965 return null;
966 }
967 }
968
969 /**
970 * Returns the source IP from a given flow rule if the rule contains
971 * the match of it.
972 *
973 * @param flowRule flow rule
974 * @return ip prefix, or null if the rule doesn't have ip match
975 */
976 private IpPrefix getSrcIpFromSelector(FlowRule flowRule) {
977 Criterion criterion = flowRule.selector().getCriterion(IPV4_SRC);
978 if (criterion != null && criterion instanceof IPCriterion) {
979 IPCriterion ip = (IPCriterion) criterion;
980 return ip.ip();
981 } else {
982 return null;
983 }
984 }
985
986 /**
987 * Returns the group ID from a given flow rule if the rule contains the
988 * treatment of it.
989 *
990 * @param flowRule flow rule
991 * @return group id, or null if the rule doesn't have group instruction
992 */
993 private GroupId getGroupIdFromTreatment(FlowRule flowRule) {
994 Instruction instruction = flowRule.treatment().allInstructions().stream()
995 .filter(inst -> inst instanceof Instructions.GroupInstruction)
996 .findFirst()
997 .orElse(null);
998
999 if (instruction == null) {
1000 return null;
1001 }
1002
1003 return ((Instructions.GroupInstruction) instruction).groupId();
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001004 }
1005
1006 /**
Hyunsun Moon4a915152016-01-14 16:56:26 -08001007 * Creates a new group for a given service.
1008 *
1009 * @param deviceId device id to create a group
1010 * @param service cord service
1011 * @return group id, or null if it fails to create
1012 */
1013 private GroupId createServiceGroup(DeviceId deviceId, CordService service) {
1014 checkNotNull(service);
1015
1016 GroupKey groupKey = getGroupKey(service.id());
1017 Group group = groupService.getGroup(deviceId, groupKey);
1018 GroupId groupId = getGroupId(service.id(), deviceId);
1019
1020 if (group != null) {
1021 log.debug("Group {} is already exist in {}", service.id(), deviceId);
1022 return groupId;
1023 }
1024
1025 GroupBuckets buckets = getServiceGroupBuckets(deviceId, service.segmentationId(), service.hosts());
1026 GroupDescription groupDescription = new DefaultGroupDescription(
1027 deviceId,
1028 GroupDescription.Type.SELECT,
1029 buckets,
1030 groupKey,
1031 groupId.id(),
1032 appId);
1033
1034 groupService.addGroup(groupDescription);
1035
1036 return groupId;
1037 }
1038
1039 /**
1040 * Returns group buckets for a given device.
1041 *
1042 * @param deviceId device id
1043 * @param tunnelId tunnel id
1044 * @param hosts list of host
1045 * @return group buckets
1046 */
1047 private GroupBuckets getServiceGroupBuckets(DeviceId deviceId, long tunnelId, Map<Host, IpAddress> hosts) {
1048 List<GroupBucket> buckets = Lists.newArrayList();
1049
1050 for (Map.Entry<Host, IpAddress> entry : hosts.entrySet()) {
1051 Host host = entry.getKey();
1052 Ip4Address remoteIp = entry.getValue().getIp4Address();
1053 DeviceId hostDevice = host.location().deviceId();
1054
1055 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
1056 .builder()
1057 .setEthDst(host.mac());
1058
1059 if (deviceId.equals(hostDevice)) {
1060 tBuilder.setOutput(host.location().port());
1061 } else {
1062 ExtensionTreatment tunnelDst = getTunnelDst(deviceId, remoteIp);
1063 if (tunnelDst == null) {
1064 continue;
1065 }
1066
1067 tBuilder.extension(tunnelDst, deviceId)
1068 .setTunnelId(tunnelId)
1069 .setOutput(getTunnelPort(hostDevice));
1070 }
1071
1072 buckets.add(DefaultGroupBucket.createSelectGroupBucket(tBuilder.build()));
1073 }
1074
1075 return new GroupBuckets(buckets);
1076 }
1077
1078 /**
1079 * Returns globally unique group ID.
1080 *
1081 * @param serviceId service id
1082 * @param deviceId device id
1083 * @return group id
1084 */
1085 private GroupId getGroupId(CordServiceId serviceId, DeviceId deviceId) {
1086 return new DefaultGroupId(Objects.hash(serviceId, deviceId));
1087 }
1088
1089 /**
1090 * Returns group key of a service.
1091 *
1092 * @param serviceId service id
1093 * @return group key
1094 */
1095 private GroupKey getGroupKey(CordServiceId serviceId) {
1096 return new DefaultGroupKey(serviceId.id().getBytes());
1097 }
1098
1099 /**
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001100 * Returns extension instruction to set tunnel destination.
1101 *
1102 * @param deviceId device id
1103 * @param remoteIp tunnel destination address
1104 * @return extension treatment or null if it fails to get instruction
1105 */
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001106 private ExtensionTreatment getTunnelDst(DeviceId deviceId, Ip4Address remoteIp) {
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001107 try {
1108 Driver driver = driverService.getDriver(deviceId);
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001109 DefaultDriverData driverData = new DefaultDriverData(driver, deviceId);
1110 DriverHandler handler = new DefaultDriverHandler(driverData);
1111 ExtensionTreatmentResolver resolver = handler.behaviour(ExtensionTreatmentResolver.class);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001112
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001113 ExtensionTreatment treatment =
1114 resolver.getExtensionInstruction(NICIRA_SET_TUNNEL_DST.type());
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001115 treatment.setPropertyValue("tunnelDst", remoteIp);
1116
1117 return treatment;
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001118 } catch (ItemNotFoundException | UnsupportedOperationException |
1119 ExtensionPropertyException e) {
1120 log.error("Failed to get extension instruction {}", deviceId);
Hyunsun Moon9f0814b2015-11-04 17:34:35 -08001121 return null;
1122 }
1123 }
1124}
Hyunsun Moonc71231d2015-12-16 20:53:23 -08001125