blob: 582503a035d7cfc853c1c0b1f2a4e74eb7c9e827 [file] [log] [blame]
sangho6a9ff0d2017-03-27 11:23:37 +09001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002* Copyright 2017-present Open Networking Foundation
sangho6a9ff0d2017-03-27 11:23:37 +09003*
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*/
16
17package org.onosproject.openstacknetworking.impl;
18
19import com.google.common.base.Strings;
sangho2e97be02017-07-03 18:18:27 +090020import com.google.common.collect.Maps;
21import com.google.common.collect.Sets;
sangho6a9ff0d2017-03-27 11:23:37 +090022import org.apache.felix.scr.annotations.Activate;
23import org.apache.felix.scr.annotations.Component;
24import org.apache.felix.scr.annotations.Deactivate;
sangho0248ca22017-05-31 13:22:47 +090025import org.apache.felix.scr.annotations.Modified;
26import org.apache.felix.scr.annotations.Property;
sangho6a9ff0d2017-03-27 11:23:37 +090027import org.apache.felix.scr.annotations.Reference;
28import org.apache.felix.scr.annotations.ReferenceCardinality;
29import org.onlab.packet.Ethernet;
30import org.onlab.packet.IPv4;
31import org.onlab.packet.Ip4Address;
32import org.onlab.packet.Ip4Prefix;
33import org.onlab.packet.IpPrefix;
34import org.onlab.packet.TpPort;
sangho0248ca22017-05-31 13:22:47 +090035import org.onlab.util.Tools;
36import org.onosproject.cfg.ComponentConfigService;
sangho6a9ff0d2017-03-27 11:23:37 +090037import org.onosproject.core.ApplicationId;
38import org.onosproject.core.CoreService;
39import org.onosproject.mastership.MastershipService;
40import org.onosproject.net.flow.DefaultTrafficSelector;
41import org.onosproject.net.flow.DefaultTrafficTreatment;
42import org.onosproject.net.flow.TrafficSelector;
sangho6a9ff0d2017-03-27 11:23:37 +090043import org.onosproject.openstacknetworking.api.InstancePort;
44import org.onosproject.openstacknetworking.api.InstancePortEvent;
45import org.onosproject.openstacknetworking.api.InstancePortListener;
46import org.onosproject.openstacknetworking.api.InstancePortService;
sanghodc375372017-06-08 10:41:30 +090047import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
sangho6a9ff0d2017-03-27 11:23:37 +090048import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
49import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
50import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
51import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupEvent;
52import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupListener;
53import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupService;
54import org.openstack4j.model.network.Port;
55import org.openstack4j.model.network.SecurityGroup;
56import org.openstack4j.model.network.SecurityGroupRule;
57import org.openstack4j.openstack.networking.domain.NeutronSecurityGroupRule;
sangho0248ca22017-05-31 13:22:47 +090058import org.osgi.service.component.ComponentContext;
sangho6a9ff0d2017-03-27 11:23:37 +090059import org.slf4j.Logger;
60
sangho6a9ff0d2017-03-27 11:23:37 +090061import java.util.Collections;
sangho0248ca22017-05-31 13:22:47 +090062import java.util.Dictionary;
sangho2e97be02017-07-03 18:18:27 +090063import java.util.Map;
sangho6a9ff0d2017-03-27 11:23:37 +090064import java.util.Objects;
65import java.util.Set;
66import java.util.concurrent.ExecutorService;
67import java.util.stream.Collectors;
68
69import static java.util.concurrent.Executors.newSingleThreadExecutor;
70import static org.onlab.util.Tools.groupedThreads;
sanghodc375372017-06-08 10:41:30 +090071import static org.onosproject.openstacknetworking.api.Constants.ACL_TABLE;
sangho6a9ff0d2017-03-27 11:23:37 +090072import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
73import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ACL_RULE;
74import static org.slf4j.LoggerFactory.getLogger;
75
76/**
77 * Populates flow rules to handle OpenStack SecurityGroups.
78 */
79@Component(immediate = true)
80public class OpenstackSecurityGroupHandler {
81
82 private final Logger log = getLogger(getClass());
83
sangho0248ca22017-05-31 13:22:47 +090084 private static final boolean USE_SECURITY_GROUP = false;
85
86 @Property(name = "useSecurityGroup", boolValue = USE_SECURITY_GROUP,
87 label = "Apply OpenStack security group rule for VM traffic")
88 private boolean useSecurityGroup = USE_SECURITY_GROUP;
89
sangho6a9ff0d2017-03-27 11:23:37 +090090 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
91 protected CoreService coreService;
92
93 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
94 protected InstancePortService instancePortService;
95
96 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
97 protected MastershipService mastershipService;
98
99 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moonae51e732017-04-25 17:46:21 +0900100 protected OpenstackNetworkService osNetService;
sangho6a9ff0d2017-03-27 11:23:37 +0900101
102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
103 protected OpenstackSecurityGroupService securityGroupService;
104
105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sanghodc375372017-06-08 10:41:30 +0900106 protected OpenstackFlowRuleService osFlowRuleService;
sangho6a9ff0d2017-03-27 11:23:37 +0900107
sangho0248ca22017-05-31 13:22:47 +0900108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
109 protected ComponentConfigService configService;
110
sangho6a9ff0d2017-03-27 11:23:37 +0900111 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
112 private final OpenstackNetworkListener portListener = new InternalOpenstackPortListener();
113 private final OpenstackSecurityGroupListener securityGroupListener = new InternalSecurityGroupListener();
114 private ApplicationId appId;
115
116 private final ExecutorService eventExecutor = newSingleThreadExecutor(
117 groupedThreads(this.getClass().getSimpleName(), "event-handler"));
118
119 private static final String PROTO_ICMP = "ICMP";
120 private static final String PROTO_TCP = "TCP";
121 private static final String PROTO_UDP = "UDP";
122 private static final String ETHTYPE_IPV4 = "IPV4";
123 private static final String EGRESS = "EGRESS";
124 private static final String INGRESS = "INGRESS";
125 private static final IpPrefix IP_PREFIX_ANY = Ip4Prefix.valueOf("0.0.0.0/0");
126
127 @Activate
128 protected void activate() {
129 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
130 instancePortService.addListener(instancePortListener);
131 securityGroupService.addListener(securityGroupListener);
Hyunsun Moonae51e732017-04-25 17:46:21 +0900132 osNetService.addListener(portListener);
sangho0248ca22017-05-31 13:22:47 +0900133 configService.registerProperties(getClass());
sangho6a9ff0d2017-03-27 11:23:37 +0900134
135 log.info("Started");
136 }
137
138 @Deactivate
139 protected void deactivate() {
140 instancePortService.removeListener(instancePortListener);
141 securityGroupService.removeListener(securityGroupListener);
Hyunsun Moonae51e732017-04-25 17:46:21 +0900142 osNetService.removeListener(portListener);
sangho0248ca22017-05-31 13:22:47 +0900143 configService.unregisterProperties(getClass(), false);
sangho6a9ff0d2017-03-27 11:23:37 +0900144 eventExecutor.shutdown();
145
146 log.info("Stopped");
147 }
148
sangho0248ca22017-05-31 13:22:47 +0900149 @Modified
150 protected void modified(ComponentContext context) {
151 Dictionary<?, ?> properties = context.getProperties();
152 Boolean flag;
153
154 flag = Tools.isPropertyEnabled(properties, "useSecurityGroup");
155 if (flag == null) {
156 log.info("useSecurityGroup is not configured, " +
157 "using current value of {}", useSecurityGroup);
158 } else {
159 useSecurityGroup = flag;
160 log.info("Configured. useSecurityGroup is {}",
161 useSecurityGroup ? "enabled" : "disabled");
162 }
163
164 resetSecurityGroupRules();
165 }
166
sangho6a9ff0d2017-03-27 11:23:37 +0900167 private void setSecurityGroupRules(InstancePort instPort, Port port, boolean install) {
168 port.getSecurityGroups().forEach(sgId -> {
sangho6a9ff0d2017-03-27 11:23:37 +0900169 SecurityGroup sg = securityGroupService.securityGroup(sgId);
170 if (sg == null) {
171 log.error("Security Group Not Found : {}", sgId);
172 return;
173 }
174 sg.getRules().forEach(sgRule -> updateSecurityGroupRule(instPort, port, sgRule, install));
Hyunsun Moonae51e732017-04-25 17:46:21 +0900175 final String action = install ? "Installed " : "Removed ";
176 log.debug(action + "security group rule ID : " + sgId);
sangho6a9ff0d2017-03-27 11:23:37 +0900177 });
178 }
179
180 private void updateSecurityGroupRule(InstancePort instPort, Port port, SecurityGroupRule sgRule, boolean install) {
sangho2e97be02017-07-03 18:18:27 +0900181
sangho6a9ff0d2017-03-27 11:23:37 +0900182 if (sgRule.getRemoteGroupId() != null && !sgRule.getRemoteGroupId().isEmpty()) {
183 getRemoteInstPorts(port.getTenantId(), sgRule.getRemoteGroupId())
184 .forEach(rInstPort -> {
185 populateSecurityGroupRule(sgRule, instPort, rInstPort.ipAddress().toIpPrefix(), install);
186 populateSecurityGroupRule(sgRule, rInstPort, instPort.ipAddress().toIpPrefix(), install);
187
188 SecurityGroupRule rSgRule = new NeutronSecurityGroupRule.SecurityGroupRuleConcreteBuilder()
189 .from(sgRule)
190 .direction(sgRule.getDirection().toUpperCase().equals(EGRESS) ? INGRESS : EGRESS).build();
191 populateSecurityGroupRule(rSgRule, instPort, rInstPort.ipAddress().toIpPrefix(), install);
192 populateSecurityGroupRule(rSgRule, rInstPort, instPort.ipAddress().toIpPrefix(), install);
193 });
194 } else {
195 populateSecurityGroupRule(sgRule, instPort, sgRule.getRemoteIpPrefix() == null ? IP_PREFIX_ANY :
196 IpPrefix.valueOf(sgRule.getRemoteIpPrefix()), install);
197 }
198 }
199
200 private void populateSecurityGroupRule(SecurityGroupRule sgRule, InstancePort instPort,
201 IpPrefix remoteIp, boolean install) {
sangho2e97be02017-07-03 18:18:27 +0900202 Set<TrafficSelector> selectors = buildSelectors(sgRule,
203 Ip4Address.valueOf(instPort.ipAddress().toInetAddress()), remoteIp);
204 if (selectors == null || selectors.isEmpty()) {
sangho6a9ff0d2017-03-27 11:23:37 +0900205 return;
206 }
207
sangho2e97be02017-07-03 18:18:27 +0900208 selectors.forEach(selector -> {
209 osFlowRuleService.setRule(appId,
210 instPort.deviceId(),
211 selector,
212 DefaultTrafficTreatment.builder().build(),
213 PRIORITY_ACL_RULE,
214 ACL_TABLE,
215 install);
216 });
sangho6a9ff0d2017-03-27 11:23:37 +0900217 }
218
219 /**
220 * Returns a set of host IP addresses engaged with supplied security group ID.
221 * It only searches a VM in the same tenant boundary.
222 *
223 * @param tenantId tenant id
224 * @param sgId security group id
225 * @return set of ip addresses
226 */
227 private Set<InstancePort> getRemoteInstPorts(String tenantId, String sgId) {
228 Set<InstancePort> remoteInstPorts;
229
Hyunsun Moonae51e732017-04-25 17:46:21 +0900230 remoteInstPorts = osNetService.ports().stream()
sangho6a9ff0d2017-03-27 11:23:37 +0900231 .filter(port -> port.getTenantId().equals(tenantId))
232 .filter(port -> port.getSecurityGroups().contains(sgId))
233 .map(port -> instancePortService.instancePort(port.getId()))
234 .filter(instPort -> instPort != null && instPort.ipAddress() != null)
235 .collect(Collectors.toSet());
236
237 return Collections.unmodifiableSet(remoteInstPorts);
238 }
239
sangho2e97be02017-07-03 18:18:27 +0900240 private Set<TrafficSelector> buildSelectors(SecurityGroupRule sgRule,
241 Ip4Address vmIp,
242 IpPrefix remoteIp) {
243 if (remoteIp != null && remoteIp.equals(IpPrefix.valueOf(vmIp, 32))) {
244 // do nothing if the remote IP is my IP
245 return null;
246 }
247
248 Set<TrafficSelector> selectorSet = Sets.newHashSet();
249
250 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
251 buildMatchs(sBuilder, sgRule, vmIp, remoteIp);
252
253 if (sgRule.getPortRangeMax() != null && sgRule.getPortRangeMin() != null &&
254 sgRule.getPortRangeMin() < sgRule.getPortRangeMax()) {
255 Map<TpPort, TpPort> portRangeMatchMap = buildPortRangeMatches(sgRule.getPortRangeMin(),
256 sgRule.getPortRangeMax());
257 portRangeMatchMap.entrySet().forEach(entry -> {
258
259 if (sgRule.getProtocol().toUpperCase().equals(PROTO_TCP)) {
260 if (sgRule.getDirection().toUpperCase().equals(EGRESS)) {
261 sBuilder.matchTcpSrcMasked(entry.getKey(), entry.getValue());
262 } else {
263 sBuilder.matchTcpDstMasked(entry.getKey(), entry.getValue());
264 }
265 } else if (sgRule.getProtocol().toUpperCase().equals(PROTO_UDP)) {
266 if (sgRule.getDirection().toUpperCase().equals(EGRESS)) {
267 sBuilder.matchUdpSrcMasked(entry.getKey(), entry.getValue());
268 } else {
269 sBuilder.matchUdpDstMasked(entry.getKey(), entry.getValue());
270 }
271 }
272
273 selectorSet.add(sBuilder.build());
274 }
275 );
276 } else {
277 selectorSet.add(sBuilder.build());
278 }
279
280 return selectorSet;
281 }
282
sangho6a9ff0d2017-03-27 11:23:37 +0900283 private void buildMatchs(TrafficSelector.Builder sBuilder, SecurityGroupRule sgRule,
284 Ip4Address vmIp, IpPrefix remoteIp) {
285 buildMatchEthType(sBuilder, sgRule.getEtherType());
286 buildMatchDirection(sBuilder, sgRule.getDirection(), vmIp);
287 buildMatchProto(sBuilder, sgRule.getProtocol());
288 buildMatchPort(sBuilder, sgRule.getProtocol(), sgRule.getDirection(),
sangho2e97be02017-07-03 18:18:27 +0900289 sgRule.getPortRangeMin() == null ? 0 : sgRule.getPortRangeMin(),
290 sgRule.getPortRangeMax() == null ? 0 : sgRule.getPortRangeMax());
sangho6a9ff0d2017-03-27 11:23:37 +0900291 buildMatchRemoteIp(sBuilder, remoteIp, sgRule.getDirection());
292 if (sgRule.getRemoteGroupId() != null && sgRule.getRemoteGroupId().isEmpty()) {
293 buildMatchRemoteIp(sBuilder, remoteIp, sgRule.getDirection());
294 }
295 }
296
297 private void buildMatchDirection(TrafficSelector.Builder sBuilder,
298 String direction,
299 Ip4Address vmIp) {
300 if (direction.toUpperCase().equals(EGRESS)) {
301 sBuilder.matchIPSrc(IpPrefix.valueOf(vmIp, 32));
302 } else {
303 sBuilder.matchIPDst(IpPrefix.valueOf(vmIp, 32));
304 }
305 }
306
307 private void buildMatchEthType(TrafficSelector.Builder sBuilder, String etherType) {
308 // Either IpSrc or IpDst (or both) is set by default, and we need to set EthType as IPv4.
309 sBuilder.matchEthType(Ethernet.TYPE_IPV4);
310 if (etherType != null && !Objects.equals(etherType, "null") &&
311 !etherType.toUpperCase().equals(ETHTYPE_IPV4)) {
312 log.debug("EthType {} is not supported yet in Security Group", etherType);
313 }
314 }
315
316 private void buildMatchRemoteIp(TrafficSelector.Builder sBuilder, IpPrefix remoteIpPrefix, String direction) {
317 if (remoteIpPrefix != null && !remoteIpPrefix.getIp4Prefix().equals(IP_PREFIX_ANY)) {
318 if (direction.toUpperCase().equals(EGRESS)) {
319 sBuilder.matchIPDst(remoteIpPrefix);
320 } else {
321 sBuilder.matchIPSrc(remoteIpPrefix);
322 }
323 }
324 }
325
326 private void buildMatchProto(TrafficSelector.Builder sBuilder, String protocol) {
327 if (protocol != null) {
328 switch (protocol.toUpperCase()) {
329 case PROTO_ICMP:
330 sBuilder.matchIPProtocol(IPv4.PROTOCOL_ICMP);
331 break;
332 case PROTO_TCP:
333 sBuilder.matchIPProtocol(IPv4.PROTOCOL_TCP);
334 break;
335 case PROTO_UDP:
336 sBuilder.matchIPProtocol(IPv4.PROTOCOL_UDP);
337 break;
338 default:
339 }
340 }
341 }
342
343 private void buildMatchPort(TrafficSelector.Builder sBuilder, String protocol, String direction,
344 int portMin, int portMax) {
345 if (portMin > 0 && portMax > 0 && portMin == portMax) {
346 if (protocol.toUpperCase().equals(PROTO_TCP)) {
347 if (direction.toUpperCase().equals(EGRESS)) {
348 sBuilder.matchTcpSrc(TpPort.tpPort(portMax));
349 } else {
350 sBuilder.matchTcpDst(TpPort.tpPort(portMax));
351 }
352 } else if (protocol.toUpperCase().equals(PROTO_UDP)) {
353 if (direction.toUpperCase().equals(EGRESS)) {
354 sBuilder.matchUdpSrc(TpPort.tpPort(portMax));
355 } else {
356 sBuilder.matchUdpDst(TpPort.tpPort(portMax));
357 }
358 }
359 }
360 }
361
sangho0248ca22017-05-31 13:22:47 +0900362 private void resetSecurityGroupRules() {
363
364 if (useSecurityGroup) {
365 securityGroupService.securityGroups().forEach(securityGroup ->
366 securityGroup.getRules().forEach(this::securityGroupRuleAdded));
367 } else {
368 securityGroupService.securityGroups().forEach(securityGroup ->
369 securityGroup.getRules().forEach(this::securityGroupRuleRemoved));
370 }
371
372 log.info("Reset security group info " + (useSecurityGroup ? " with " : " without") + " Security Group");
373 }
374
375 private void securityGroupRuleAdded(SecurityGroupRule sgRule) {
376 osNetService.ports().stream()
377 .filter(port -> port.getSecurityGroups().contains(sgRule.getSecurityGroupId()))
378 .forEach(port -> {
379 updateSecurityGroupRule(
380 instancePortService.instancePort(port.getId()),
381 port, sgRule, true);
382 log.debug("Applied security group rule {} to port {}",
383 sgRule.getId(), port.getId());
384 });
385 }
386
387 private void securityGroupRuleRemoved(SecurityGroupRule sgRule) {
388 osNetService.ports().stream()
389 .filter(port -> port.getSecurityGroups().contains(sgRule.getSecurityGroupId()))
390 .forEach(port -> {
391 updateSecurityGroupRule(
392 instancePortService.instancePort(port.getId()),
393 port, sgRule, false);
394 log.debug("Removed security group rule {} from port {}",
395 sgRule.getId(), port.getId());
396 });
397 }
398
sangho2e97be02017-07-03 18:18:27 +0900399 private int binLower(String binStr, int bits) {
400 String outBin = binStr.substring(0, 16 - bits);
401 for (int i = 0; i < bits; i++) {
402 outBin += "0";
403 }
404
405 return Integer.parseInt(outBin, 2);
406 }
407
408 private int binHigher(String binStr, int bits) {
409 String outBin = binStr.substring(0, 16 - bits);
410 for (int i = 0; i < bits; i++) {
411 outBin += "1";
412 }
413
414 return Integer.parseInt(outBin, 2);
415 }
416
417 private int testMasks(String binStr, int start, int end) {
418 int mask = 0;
419 for (; mask <= 16; mask++) {
420 int maskStart = binLower(binStr, mask);
421 int maskEnd = binHigher(binStr, mask);
422 if (maskStart < start || maskEnd > end) {
423 return mask - 1;
424 }
425 }
426
427 return mask;
428 }
429
430 private String getMask(int bits) {
431 switch (bits) {
432 case 0: return "ffff";
433 case 1: return "fffe";
434 case 2: return "fffc";
435 case 3: return "fff8";
436 case 4: return "fff0";
437 case 5: return "ffe0";
438 case 6: return "ffc0";
439 case 7: return "ff80";
440 case 8: return "ff00";
441 case 9: return "fe00";
442 case 10: return "fc00";
443 case 11: return "f800";
444 case 12: return "f000";
445 case 13: return "e000";
446 case 14: return "c000";
447 case 15: return "8000";
448 case 16: return "0000";
449 default: return null;
450 }
451 }
452
453 private Map<TpPort, TpPort> buildPortRangeMatches(int portMin, int portMax) {
454
455 boolean processing = true;
456 int start = portMin;
457 Map<TpPort, TpPort> portMaskMap = Maps.newHashMap();
458 while (processing) {
459 String minStr = Integer.toBinaryString(start);
460 String binStrMinPadded = "0000000000000000".substring(minStr.length()) + minStr;
461
462 int mask = testMasks(binStrMinPadded, start, portMax);
463 int maskStart = binLower(binStrMinPadded, mask);
464 int maskEnd = binHigher(binStrMinPadded, mask);
465
466 log.debug("start : {} port/mask = {} / {} ", start, getMask(mask), maskStart);
467 portMaskMap.put(TpPort.tpPort(maskStart), TpPort.tpPort(Integer.parseInt(getMask(mask), 16)));
468
469 start = maskEnd + 1;
470 if (start > portMax) {
471 processing = false;
472 }
473 }
474
475 return portMaskMap;
476 }
477
sangho6a9ff0d2017-03-27 11:23:37 +0900478 private class InternalInstancePortListener implements InstancePortListener {
479
480 @Override
481 public boolean isRelevant(InstancePortEvent event) {
482 InstancePort instPort = event.subject();
sangho0248ca22017-05-31 13:22:47 +0900483 if (!useSecurityGroup) {
484 return false;
485 }
sangho6a9ff0d2017-03-27 11:23:37 +0900486 return mastershipService.isLocalMaster(instPort.deviceId());
487 }
488
489 @Override
490 public void event(InstancePortEvent event) {
491 InstancePort instPort = event.subject();
492 switch (event.type()) {
493 case OPENSTACK_INSTANCE_PORT_UPDATED:
494 case OPENSTACK_INSTANCE_PORT_DETECTED:
Hyunsun Moonae51e732017-04-25 17:46:21 +0900495 log.debug("Instance port detected MAC:{} IP:{}",
496 instPort.macAddress(),
497 instPort.ipAddress());
sangho6a9ff0d2017-03-27 11:23:37 +0900498 eventExecutor.execute(() -> {
Hyunsun Moonae51e732017-04-25 17:46:21 +0900499 setSecurityGroupRules(instPort,
500 osNetService.port(event.subject().portId()),
501 true);
sangho6a9ff0d2017-03-27 11:23:37 +0900502 });
503 break;
504 case OPENSTACK_INSTANCE_PORT_VANISHED:
Hyunsun Moonae51e732017-04-25 17:46:21 +0900505 log.debug("Instance port vanished MAC:{} IP:{}",
506 instPort.macAddress(),
507 instPort.ipAddress());
sangho6a9ff0d2017-03-27 11:23:37 +0900508 eventExecutor.execute(() -> {
Hyunsun Moonae51e732017-04-25 17:46:21 +0900509 setSecurityGroupRules(instPort,
510 osNetService.port(event.subject().portId()),
511 false);
sangho6a9ff0d2017-03-27 11:23:37 +0900512 });
513 break;
514 default:
515 break;
516 }
517 }
sangho6a9ff0d2017-03-27 11:23:37 +0900518 }
519
520 private class InternalOpenstackPortListener implements OpenstackNetworkListener {
521
522 @Override
523 public boolean isRelevant(OpenstackNetworkEvent event) {
Hyunsun Moonae51e732017-04-25 17:46:21 +0900524 if (event.port() == null || !Strings.isNullOrEmpty(event.port().getId())) {
sangho6a9ff0d2017-03-27 11:23:37 +0900525 return false;
526 }
Hyunsun Moonae51e732017-04-25 17:46:21 +0900527 if (event.securityGroupId() == null ||
528 securityGroupService.securityGroup(event.securityGroupId()) == null) {
529 return false;
530 }
531 if (instancePortService.instancePort(event.port().getId()) == null) {
532 return false;
533 }
sangho0248ca22017-05-31 13:22:47 +0900534 if (!useSecurityGroup) {
535 return false;
536 }
Hyunsun Moonae51e732017-04-25 17:46:21 +0900537 return true;
sangho6a9ff0d2017-03-27 11:23:37 +0900538 }
539
540 @Override
541 public void event(OpenstackNetworkEvent event) {
Hyunsun Moonae51e732017-04-25 17:46:21 +0900542 Port osPort = event.port();
543 InstancePort instPort = instancePortService.instancePort(osPort.getId());
544 SecurityGroup osSg = securityGroupService.securityGroup(event.securityGroupId());
545
sangho6a9ff0d2017-03-27 11:23:37 +0900546 switch (event.type()) {
Hyunsun Moonae51e732017-04-25 17:46:21 +0900547 case OPENSTACK_PORT_SECURITY_GROUP_ADDED:
548 eventExecutor.execute(() -> {
549 osSg.getRules().forEach(sgRule -> {
550 updateSecurityGroupRule(instPort, osPort, sgRule, true);
551 });
552 log.info("Added security group {} to port {}",
553 event.securityGroupId(), event.port().getId());
554 });
sangho6a9ff0d2017-03-27 11:23:37 +0900555 break;
Hyunsun Moonae51e732017-04-25 17:46:21 +0900556 case OPENSTACK_PORT_SECURITY_GROUP_REMOVED:
557 eventExecutor.execute(() -> {
558 osSg.getRules().forEach(sgRule -> {
559 updateSecurityGroupRule(instPort, osPort, sgRule, false);
560 });
561 log.info("Removed security group {} from port {}",
562 event.securityGroupId(), event.port().getId());
563 });
sangho6a9ff0d2017-03-27 11:23:37 +0900564 break;
565 default:
Hyunsun Moonae51e732017-04-25 17:46:21 +0900566 // do nothing for the other events
sangho6a9ff0d2017-03-27 11:23:37 +0900567 break;
568 }
569 }
sangho6a9ff0d2017-03-27 11:23:37 +0900570 }
571
572 private class InternalSecurityGroupListener implements OpenstackSecurityGroupListener {
573
574 @Override
sangho0248ca22017-05-31 13:22:47 +0900575 public boolean isRelevant(OpenstackSecurityGroupEvent event) {
576 if (!useSecurityGroup) {
577 return false;
578 }
579 return true;
580 }
581
582 @Override
sangho6a9ff0d2017-03-27 11:23:37 +0900583 public void event(OpenstackSecurityGroupEvent event) {
584 switch (event.type()) {
sangho6a9ff0d2017-03-27 11:23:37 +0900585 case OPENSTACK_SECURITY_GROUP_RULE_CREATED:
586 SecurityGroupRule securityGroupRuleToAdd = event.securityGroupRule();
587 eventExecutor.execute(() -> {
sangho6a9ff0d2017-03-27 11:23:37 +0900588 securityGroupRuleAdded(securityGroupRuleToAdd);
Hyunsun Moonae51e732017-04-25 17:46:21 +0900589 log.info("Applied new security group rule {} to ports",
590 securityGroupRuleToAdd.getId());
sangho6a9ff0d2017-03-27 11:23:37 +0900591 });
592 break;
593
594 case OPENSTACK_SECURITY_GROUP_RULE_REMOVED:
595 SecurityGroupRule securityGroupRuleToRemove = event.securityGroupRule();
596 eventExecutor.execute(() -> {
sangho6a9ff0d2017-03-27 11:23:37 +0900597 securityGroupRuleRemoved(securityGroupRuleToRemove);
Hyunsun Moonae51e732017-04-25 17:46:21 +0900598 log.info("Removed security group rule {} from ports",
599 securityGroupRuleToRemove.getId());
sangho6a9ff0d2017-03-27 11:23:37 +0900600 });
601 break;
Hyunsun Moonae51e732017-04-25 17:46:21 +0900602 case OPENSTACK_SECURITY_GROUP_CREATED:
603 case OPENSTACK_SECURITY_GROUP_REMOVED:
sangho6a9ff0d2017-03-27 11:23:37 +0900604 default:
Hyunsun Moonae51e732017-04-25 17:46:21 +0900605 // do nothing
606 break;
sangho6a9ff0d2017-03-27 11:23:37 +0900607 }
608 }
sangho6a9ff0d2017-03-27 11:23:37 +0900609 }
610}