blob: dc734a9fe46af5ce56950df3ae4c5ab74eae49c4 [file] [log] [blame]
sangho6a9ff0d2017-03-27 11:23:37 +09001/*
Jian Li26949762018-03-30 15:46:37 +09002 * Copyright 2017-present Open Networking Foundation
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 */
sangho6a9ff0d2017-03-27 11:23:37 +090016
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.onlab.packet.Ethernet;
23import org.onlab.packet.IPv4;
24import org.onlab.packet.Ip4Address;
25import org.onlab.packet.Ip4Prefix;
26import org.onlab.packet.IpPrefix;
27import org.onlab.packet.TpPort;
Jian Lie8b28db2018-10-17 14:04:09 +090028import org.onlab.packet.VlanId;
Jian Liac30e272018-10-18 23:08:03 +090029import org.onlab.util.KryoNamespace;
sangho0248ca22017-05-31 13:22:47 +090030import org.onlab.util.Tools;
31import org.onosproject.cfg.ComponentConfigService;
sangho1aaa7882017-05-31 13:22:47 +090032import org.onosproject.cluster.ClusterService;
33import org.onosproject.cluster.LeadershipService;
34import org.onosproject.cluster.NodeId;
sangho6a9ff0d2017-03-27 11:23:37 +090035import org.onosproject.core.ApplicationId;
36import org.onosproject.core.CoreService;
37import org.onosproject.mastership.MastershipService;
sangho1aaa7882017-05-31 13:22:47 +090038import org.onosproject.net.DeviceId;
39import org.onosproject.net.driver.DriverService;
sangho6a9ff0d2017-03-27 11:23:37 +090040import org.onosproject.net.flow.DefaultTrafficSelector;
41import org.onosproject.net.flow.DefaultTrafficTreatment;
42import org.onosproject.net.flow.TrafficSelector;
sangho1aaa7882017-05-31 13:22:47 +090043import org.onosproject.net.flow.TrafficTreatment;
44import org.onosproject.net.flow.criteria.ExtensionSelector;
Jian Li28ec77f2018-10-31 07:07:25 +090045import org.onosproject.net.flow.instructions.ExtensionTreatment;
sangho6a9ff0d2017-03-27 11:23:37 +090046import org.onosproject.openstacknetworking.api.InstancePort;
Jian Li9d35bd62018-10-13 01:43:24 +090047import org.onosproject.openstacknetworking.api.InstancePortAdminService;
sangho6a9ff0d2017-03-27 11:23:37 +090048import org.onosproject.openstacknetworking.api.InstancePortEvent;
49import org.onosproject.openstacknetworking.api.InstancePortListener;
sanghodc375372017-06-08 10:41:30 +090050import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
sangho6a9ff0d2017-03-27 11:23:37 +090051import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
52import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
53import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
54import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupEvent;
55import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupListener;
56import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupService;
Jian Li26949762018-03-30 15:46:37 +090057import org.onosproject.openstacknetworking.util.RulePopulatorUtil;
sangho1aaa7882017-05-31 13:22:47 +090058import org.onosproject.openstacknode.api.OpenstackNodeEvent;
59import org.onosproject.openstacknode.api.OpenstackNodeListener;
sangho3dd2a8b2017-07-19 15:54:31 +090060import org.onosproject.openstacknode.api.OpenstackNodeService;
Jian Liac30e272018-10-18 23:08:03 +090061import org.onosproject.store.serializers.KryoNamespaces;
62import org.onosproject.store.service.ConsistentMap;
63import org.onosproject.store.service.Serializer;
64import org.onosproject.store.service.StorageService;
sangho6a9ff0d2017-03-27 11:23:37 +090065import org.openstack4j.model.network.Port;
66import org.openstack4j.model.network.SecurityGroup;
67import org.openstack4j.model.network.SecurityGroupRule;
Jian Liac30e272018-10-18 23:08:03 +090068import org.openstack4j.model.network.State;
69import org.openstack4j.openstack.networking.domain.NeutronAllowedAddressPair;
70import org.openstack4j.openstack.networking.domain.NeutronExtraDhcpOptCreate;
71import org.openstack4j.openstack.networking.domain.NeutronIP;
72import org.openstack4j.openstack.networking.domain.NeutronPort;
sangho6a9ff0d2017-03-27 11:23:37 +090073import org.openstack4j.openstack.networking.domain.NeutronSecurityGroupRule;
sangho0248ca22017-05-31 13:22:47 +090074import org.osgi.service.component.ComponentContext;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070075import org.osgi.service.component.annotations.Activate;
76import org.osgi.service.component.annotations.Component;
77import org.osgi.service.component.annotations.Deactivate;
78import org.osgi.service.component.annotations.Modified;
79import org.osgi.service.component.annotations.Reference;
80import org.osgi.service.component.annotations.ReferenceCardinality;
sangho6a9ff0d2017-03-27 11:23:37 +090081import org.slf4j.Logger;
82
sangho6a9ff0d2017-03-27 11:23:37 +090083import java.util.Collections;
sangho0248ca22017-05-31 13:22:47 +090084import java.util.Dictionary;
Jian Liac30e272018-10-18 23:08:03 +090085import java.util.HashSet;
86import java.util.LinkedHashMap;
sangho2e97be02017-07-03 18:18:27 +090087import java.util.Map;
sangho6a9ff0d2017-03-27 11:23:37 +090088import java.util.Objects;
89import java.util.Set;
90import java.util.concurrent.ExecutorService;
91import java.util.stream.Collectors;
92
93import static java.util.concurrent.Executors.newSingleThreadExecutor;
94import static org.onlab.util.Tools.groupedThreads;
sanghodc375372017-06-08 10:41:30 +090095import static org.onosproject.openstacknetworking.api.Constants.ACL_TABLE;
sangho1aaa7882017-05-31 13:22:47 +090096import static org.onosproject.openstacknetworking.api.Constants.CT_TABLE;
97import static org.onosproject.openstacknetworking.api.Constants.ERROR_TABLE;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070098import static org.onosproject.openstacknetworking.api.Constants.JUMP_TABLE;
sangho6a9ff0d2017-03-27 11:23:37 +090099import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
100import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ACL_RULE;
sangho1aaa7882017-05-31 13:22:47 +0900101import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_CT_DROP_RULE;
102import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_CT_HOOK_RULE;
103import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_CT_RULE;
Ray Milkey8e406512018-10-24 15:56:50 -0700104import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.USE_SECURITY_GROUP;
105import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.USE_SECURITY_GROUP_DEFAULT;
Jian Lib8cdcc12018-10-23 01:53:10 +0900106import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
Jian Libcc42282018-09-13 20:59:34 +0900107import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.computeCtMaskFlag;
108import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.computeCtStateFlag;
109import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.niciraConnTrackTreatmentBuilder;
sangho1aaa7882017-05-31 13:22:47 +0900110import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
sangho6a9ff0d2017-03-27 11:23:37 +0900111import static org.slf4j.LoggerFactory.getLogger;
112
113/**
114 * Populates flow rules to handle OpenStack SecurityGroups.
115 */
Ray Milkey8e406512018-10-24 15:56:50 -0700116@Component(
117 immediate = true,
118 property = {
119 USE_SECURITY_GROUP + ":Boolean=" + USE_SECURITY_GROUP_DEFAULT
120 }
121)
sangho6a9ff0d2017-03-27 11:23:37 +0900122public class OpenstackSecurityGroupHandler {
123
124 private final Logger log = getLogger(getClass());
125
Jian Li2b9838c2018-10-28 17:09:42 +0900126 private static final int VM_IP_PREFIX = 32;
127
Ray Milkey8e406512018-10-24 15:56:50 -0700128 /** Apply OpenStack security group rule for VM traffic. */
129 private boolean useSecurityGroup = USE_SECURITY_GROUP_DEFAULT;
sangho0248ca22017-05-31 13:22:47 +0900130
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700131 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho6a9ff0d2017-03-27 11:23:37 +0900132 protected CoreService coreService;
133
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700134 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li9d35bd62018-10-13 01:43:24 +0900135 protected InstancePortAdminService instancePortService;
sangho6a9ff0d2017-03-27 11:23:37 +0900136
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700137 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho6a9ff0d2017-03-27 11:23:37 +0900138 protected MastershipService mastershipService;
139
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700140 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moonae51e732017-04-25 17:46:21 +0900141 protected OpenstackNetworkService osNetService;
sangho6a9ff0d2017-03-27 11:23:37 +0900142
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700143 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho6a9ff0d2017-03-27 11:23:37 +0900144 protected OpenstackSecurityGroupService securityGroupService;
145
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700146 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sanghodc375372017-06-08 10:41:30 +0900147 protected OpenstackFlowRuleService osFlowRuleService;
sangho6a9ff0d2017-03-27 11:23:37 +0900148
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700149 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho0248ca22017-05-31 13:22:47 +0900150 protected ComponentConfigService configService;
151
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700152 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho3dd2a8b2017-07-19 15:54:31 +0900153 protected OpenstackNodeService osNodeService;
154
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700155 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho1aaa7882017-05-31 13:22:47 +0900156 protected DriverService driverService;
157
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700158 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho1aaa7882017-05-31 13:22:47 +0900159 protected LeadershipService leadershipService;
160
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700161 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho1aaa7882017-05-31 13:22:47 +0900162 protected ClusterService clusterService;
163
Ray Milkey0b18b722018-10-16 13:19:15 -0700164 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Liac30e272018-10-18 23:08:03 +0900165 protected StorageService storageService;
166
167 private static final KryoNamespace SERIALIZER_PORT = KryoNamespace.newBuilder()
168 .register(KryoNamespaces.API)
169 .register(Port.class)
170 .register(NeutronPort.class)
171 .register(NeutronIP.class)
172 .register(State.class)
173 .register(NeutronAllowedAddressPair.class)
174 .register(NeutronExtraDhcpOptCreate.class)
175 .register(LinkedHashMap.class)
176 .build();
Jian Li9d35bd62018-10-13 01:43:24 +0900177
Jian Libcc42282018-09-13 20:59:34 +0900178 private final InstancePortListener instancePortListener =
Jian Lia70fdb602018-11-05 01:32:22 +0900179 new InternalInstancePortListener();
Jian Libcc42282018-09-13 20:59:34 +0900180 private final OpenstackNetworkListener osNetworkListener =
Jian Lia70fdb602018-11-05 01:32:22 +0900181 new InternalOpenstackNetworkListener();
Jian Libcc42282018-09-13 20:59:34 +0900182 private final OpenstackNetworkListener osPortListener =
Jian Lia70fdb602018-11-05 01:32:22 +0900183 new InternalOpenstackPortListener();
Jian Libcc42282018-09-13 20:59:34 +0900184 private final OpenstackSecurityGroupListener securityGroupListener =
Jian Lia70fdb602018-11-05 01:32:22 +0900185 new InternalSecurityGroupListener();
sangho1aaa7882017-05-31 13:22:47 +0900186 private final OpenstackNodeListener osNodeListener = new InternalNodeListener();
Jian Liac30e272018-10-18 23:08:03 +0900187
188 private ConsistentMap<String, Port> removedOsPortStore;
189
sangho6a9ff0d2017-03-27 11:23:37 +0900190 private ApplicationId appId;
sangho1aaa7882017-05-31 13:22:47 +0900191 private NodeId localNodeId;
sangho6a9ff0d2017-03-27 11:23:37 +0900192
193 private final ExecutorService eventExecutor = newSingleThreadExecutor(
194 groupedThreads(this.getClass().getSimpleName(), "event-handler"));
195
196 private static final String PROTO_ICMP = "ICMP";
197 private static final String PROTO_TCP = "TCP";
198 private static final String PROTO_UDP = "UDP";
199 private static final String ETHTYPE_IPV4 = "IPV4";
200 private static final String EGRESS = "EGRESS";
201 private static final String INGRESS = "INGRESS";
202 private static final IpPrefix IP_PREFIX_ANY = Ip4Prefix.valueOf("0.0.0.0/0");
203
Jian Lie8b28db2018-10-17 14:04:09 +0900204 private static final String VXLAN = "VXLAN";
205 private static final String VLAN = "VLAN";
206
sangho1aaa7882017-05-31 13:22:47 +0900207 // We expose pipeline structure to SONA application considering removing pipeline soon.
sanghoshinbbeb31a2018-09-11 17:01:01 +0800208 private static final int GOTO_CONNTRACK_TABLE = CT_TABLE;
209 private static final int GOTO_JUMP_TABLE = JUMP_TABLE;
sangho1aaa7882017-05-31 13:22:47 +0900210
211 private static final int CT_COMMIT = 0;
212 private static final int CT_NO_COMMIT = 1;
213 private static final short CT_NO_RECIRC = -1;
214
215 private static final int ACTION_NONE = 0;
216 private static final int ACTION_DROP = -1;
217
sangho6a9ff0d2017-03-27 11:23:37 +0900218 @Activate
219 protected void activate() {
220 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
sangho1aaa7882017-05-31 13:22:47 +0900221 localNodeId = clusterService.getLocalNode().id();
sangho6a9ff0d2017-03-27 11:23:37 +0900222 instancePortService.addListener(instancePortListener);
223 securityGroupService.addListener(securityGroupListener);
Jian Libcc42282018-09-13 20:59:34 +0900224 osNetService.addListener(osPortListener);
225 osNetService.addListener(osNetworkListener);
sangho0248ca22017-05-31 13:22:47 +0900226 configService.registerProperties(getClass());
sangho1aaa7882017-05-31 13:22:47 +0900227 osNodeService.addListener(osNodeListener);
sangho6a9ff0d2017-03-27 11:23:37 +0900228
Jian Liac30e272018-10-18 23:08:03 +0900229 removedOsPortStore = storageService.<String, Port>consistentMapBuilder()
230 .withSerializer(Serializer.using(SERIALIZER_PORT))
231 .withName("openstack-removed-portstore")
232 .withApplicationId(appId)
233 .build();
234
sangho6a9ff0d2017-03-27 11:23:37 +0900235 log.info("Started");
236 }
237
238 @Deactivate
239 protected void deactivate() {
240 instancePortService.removeListener(instancePortListener);
241 securityGroupService.removeListener(securityGroupListener);
Jian Libcc42282018-09-13 20:59:34 +0900242 osNetService.removeListener(osNetworkListener);
243 osNetService.removeListener(osPortListener);
sangho0248ca22017-05-31 13:22:47 +0900244 configService.unregisterProperties(getClass(), false);
sangho1aaa7882017-05-31 13:22:47 +0900245 osNodeService.removeListener(osNodeListener);
sangho6a9ff0d2017-03-27 11:23:37 +0900246 eventExecutor.shutdown();
247
248 log.info("Stopped");
249 }
250
sangho0248ca22017-05-31 13:22:47 +0900251 @Modified
252 protected void modified(ComponentContext context) {
253 Dictionary<?, ?> properties = context.getProperties();
254 Boolean flag;
255
Ray Milkey8e406512018-10-24 15:56:50 -0700256 flag = Tools.isPropertyEnabled(properties, USE_SECURITY_GROUP);
sangho0248ca22017-05-31 13:22:47 +0900257 if (flag == null) {
258 log.info("useSecurityGroup is not configured, " +
259 "using current value of {}", useSecurityGroup);
260 } else {
261 useSecurityGroup = flag;
262 log.info("Configured. useSecurityGroup is {}",
263 useSecurityGroup ? "enabled" : "disabled");
264 }
265
sanghoe6457a32017-08-24 14:31:19 +0900266 securityGroupService.setSecurityGroupEnabled(useSecurityGroup);
sangho0248ca22017-05-31 13:22:47 +0900267 resetSecurityGroupRules();
268 }
269
sangho1aaa7882017-05-31 13:22:47 +0900270 private void initializeConnTrackTable(DeviceId deviceId, boolean install) {
271
272 //table=1,ip,ct_state=-trk, actions=ct(table:2)
Jian Libcc42282018-09-13 20:59:34 +0900273 long ctState = computeCtStateFlag(false, false, false);
274 long ctMask = computeCtMaskFlag(true, false, false);
sangho1aaa7882017-05-31 13:22:47 +0900275 setConnTrackRule(deviceId, ctState, ctMask, CT_NO_COMMIT, (short) GOTO_CONNTRACK_TABLE,
276 ACTION_NONE, PRIORITY_CT_HOOK_RULE, install);
277
278 //table=2,ip,nw_dst=10.10.0.2,ct_state=+trk+est,action=goto_table:3
Jian Libcc42282018-09-13 20:59:34 +0900279 ctState = computeCtStateFlag(true, false, true);
280 ctMask = computeCtMaskFlag(true, false, true);
sangho1aaa7882017-05-31 13:22:47 +0900281 setConnTrackRule(deviceId, ctState, ctMask, CT_NO_COMMIT, CT_NO_RECIRC,
282 GOTO_JUMP_TABLE, PRIORITY_CT_RULE, install);
283
284 //table=2,ip,nw_dst=10.10.0.2,ct_state=+trk+new,action=drop
Jian Libcc42282018-09-13 20:59:34 +0900285 ctState = computeCtStateFlag(true, true, false);
286 ctMask = computeCtMaskFlag(true, true, false);
sangho1aaa7882017-05-31 13:22:47 +0900287 setConnTrackRule(deviceId, ctState, ctMask, CT_NO_COMMIT, CT_NO_RECIRC,
288 ACTION_DROP, PRIORITY_CT_DROP_RULE, install);
289 }
290
Jian Libcc42282018-09-13 20:59:34 +0900291 private void setSecurityGroupRules(InstancePort instPort,
292 Port port, boolean install) {
Jian Liac30e272018-10-18 23:08:03 +0900293
294 if (!install) {
295 Port rmvPort = removedOsPortStore.asJavaMap().get(instPort.portId());
296 if (port == null && rmvPort == null) {
297 return;
298 }
299
300 if (port == null) {
301 port = rmvPort;
302 }
303 }
304
305 final Port finalPort = port;
306
sangho6a9ff0d2017-03-27 11:23:37 +0900307 port.getSecurityGroups().forEach(sgId -> {
sangho6a9ff0d2017-03-27 11:23:37 +0900308 SecurityGroup sg = securityGroupService.securityGroup(sgId);
309 if (sg == null) {
310 log.error("Security Group Not Found : {}", sgId);
311 return;
312 }
Jian Libcc42282018-09-13 20:59:34 +0900313 sg.getRules().forEach(sgRule ->
Jian Liac30e272018-10-18 23:08:03 +0900314 updateSecurityGroupRule(instPort, finalPort, sgRule, install));
Hyunsun Moonae51e732017-04-25 17:46:21 +0900315 final String action = install ? "Installed " : "Removed ";
316 log.debug(action + "security group rule ID : " + sgId);
sangho6a9ff0d2017-03-27 11:23:37 +0900317 });
318 }
319
Jian Libcc42282018-09-13 20:59:34 +0900320 private void updateSecurityGroupRule(InstancePort instPort, Port port,
321 SecurityGroupRule sgRule, boolean install) {
sangho2e97be02017-07-03 18:18:27 +0900322
Daniel Park3a140592018-06-28 18:33:10 +0900323 if (instPort == null || port == null || sgRule == null) {
324 return;
325 }
326
sangho6a9ff0d2017-03-27 11:23:37 +0900327 if (sgRule.getRemoteGroupId() != null && !sgRule.getRemoteGroupId().isEmpty()) {
Jian Lia70fdb602018-11-05 01:32:22 +0900328 getRemoteInstPorts(port, sgRule.getRemoteGroupId(), install)
Jian Libcc42282018-09-13 20:59:34 +0900329 .forEach(rInstPort -> {
Jian Lie8b28db2018-10-17 14:04:09 +0900330 populateSecurityGroupRule(sgRule, instPort, port,
Jian Libcc42282018-09-13 20:59:34 +0900331 rInstPort.ipAddress().toIpPrefix(), install);
Jian Lie8b28db2018-10-17 14:04:09 +0900332 populateSecurityGroupRule(sgRule, rInstPort, port,
Jian Libcc42282018-09-13 20:59:34 +0900333 instPort.ipAddress().toIpPrefix(), install);
sangho6a9ff0d2017-03-27 11:23:37 +0900334
Jian Libcc42282018-09-13 20:59:34 +0900335 SecurityGroupRule rSgRule =
336 new NeutronSecurityGroupRule
337 .SecurityGroupRuleConcreteBuilder()
Jian Li28ec77f2018-10-31 07:07:25 +0900338 .from(sgRule)
339 .direction(sgRule.getDirection().toUpperCase()
340 .equals(EGRESS) ? INGRESS : EGRESS)
341 .build();
Jian Lie8b28db2018-10-17 14:04:09 +0900342 populateSecurityGroupRule(rSgRule, instPort, port,
Jian Libcc42282018-09-13 20:59:34 +0900343 rInstPort.ipAddress().toIpPrefix(), install);
Jian Lie8b28db2018-10-17 14:04:09 +0900344 populateSecurityGroupRule(rSgRule, rInstPort, port,
Jian Libcc42282018-09-13 20:59:34 +0900345 instPort.ipAddress().toIpPrefix(), install);
346 });
sangho6a9ff0d2017-03-27 11:23:37 +0900347 } else {
Jian Lie8b28db2018-10-17 14:04:09 +0900348 populateSecurityGroupRule(sgRule, instPort, port,
Jian Libcc42282018-09-13 20:59:34 +0900349 sgRule.getRemoteIpPrefix() == null ? IP_PREFIX_ANY :
Jian Li28ec77f2018-10-31 07:07:25 +0900350 IpPrefix.valueOf(sgRule.getRemoteIpPrefix()), install);
sangho6a9ff0d2017-03-27 11:23:37 +0900351 }
352 }
353
Jian Libcc42282018-09-13 20:59:34 +0900354 private void populateSecurityGroupRule(SecurityGroupRule sgRule,
355 InstancePort instPort,
Jian Lie8b28db2018-10-17 14:04:09 +0900356 Port port,
357 IpPrefix remoteIp,
358 boolean install) {
sangho2e97be02017-07-03 18:18:27 +0900359 Set<TrafficSelector> selectors = buildSelectors(sgRule,
Jian Lie8b28db2018-10-17 14:04:09 +0900360 Ip4Address.valueOf(instPort.ipAddress().toInetAddress()), remoteIp, port);
sangho2e97be02017-07-03 18:18:27 +0900361 if (selectors == null || selectors.isEmpty()) {
sangho6a9ff0d2017-03-27 11:23:37 +0900362 return;
363 }
364
Jian Li28ec77f2018-10-31 07:07:25 +0900365 // XXX All egress traffic needs to go through connection tracking module,
366 // which might hurt its performance.
367 ExtensionTreatment ctTreatment =
368 niciraConnTrackTreatmentBuilder(driverService, instPort.deviceId())
369 .commit(true)
370 .build();
371
372 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
373 .extension(ctTreatment, instPort.deviceId())
374 .transition(JUMP_TABLE)
375 .build();
376
Jian Li2b9838c2018-10-28 17:09:42 +0900377 selectors.forEach(selector ->
378 osFlowRuleService.setRule(appId,
Jian Li28ec77f2018-10-31 07:07:25 +0900379 instPort.deviceId(),
380 selector, treatment,
381 PRIORITY_ACL_RULE,
382 ACL_TABLE,
383 install));
sangho6a9ff0d2017-03-27 11:23:37 +0900384 }
385
386 /**
sangho1aaa7882017-05-31 13:22:47 +0900387 * Sets connection tracking rule using OVS extension commands.
Jian Li2b9838c2018-10-28 17:09:42 +0900388 * It is not so graceful, but I don't want to make it more general because
389 * it is going to be used only here.
390 * The following is the usage of the function.
sangho1aaa7882017-05-31 13:22:47 +0900391 *
392 * @param deviceId Device ID
Jian Li2b9838c2018-10-28 17:09:42 +0900393 * @param ctState ctState: please use RulePopulatorUtil.computeCtStateFlag()
394 * to build the value
395 * @param ctMask crMask: please use RulePopulatorUtil.computeCtMaskFlag()
396 * to build the value
sangho1aaa7882017-05-31 13:22:47 +0900397 * @param commit CT_COMMIT for commit action, CT_NO_COMMIT otherwise
Jian Li2b9838c2018-10-28 17:09:42 +0900398 * @param recircTable table number for recirculation after CT actions.
399 * CT_NO_RECIRC with no recirculation
400 * @param action Additional actions. ACTION_DROP, ACTION_NONE,
401 * GOTO_XXX_TABLE are supported.
sangho1aaa7882017-05-31 13:22:47 +0900402 * @param priority priority value for the rule
403 * @param install true for insertion, false for removal
404 */
405 private void setConnTrackRule(DeviceId deviceId, long ctState, long ctMask,
406 int commit, short recircTable,
407 int action, int priority, boolean install) {
408
Jian Libcc42282018-09-13 20:59:34 +0900409 ExtensionSelector esCtSate = RulePopulatorUtil
410 .buildCtExtensionSelector(driverService, deviceId, ctState, ctMask);
sangho1aaa7882017-05-31 13:22:47 +0900411 TrafficSelector selector = DefaultTrafficSelector.builder()
412 .extension(esCtSate, deviceId)
413 .matchEthType(Ethernet.TYPE_IPV4)
414 .build();
415
416 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
417
418 if (commit == CT_COMMIT || recircTable > 0) {
419 RulePopulatorUtil.NiriraConnTrackTreatmentBuilder natTreatmentBuilder =
Jian Libcc42282018-09-13 20:59:34 +0900420 niciraConnTrackTreatmentBuilder(driverService, deviceId);
sangho1aaa7882017-05-31 13:22:47 +0900421 natTreatmentBuilder.natAction(false);
422 if (commit == CT_COMMIT) {
423 natTreatmentBuilder.commit(true);
424 } else {
425 natTreatmentBuilder.commit(false);
426 }
427 if (recircTable > 0) {
428 natTreatmentBuilder.table(recircTable);
429 }
430 tb.extension(natTreatmentBuilder.build(), deviceId);
431 } else if (action == ACTION_DROP) {
432 tb.drop();
433 }
434
sanghoshinbbeb31a2018-09-11 17:01:01 +0800435 if (action != ACTION_NONE && action != ACTION_DROP) {
sangho1aaa7882017-05-31 13:22:47 +0900436 tb.transition(action);
437 }
438
439 int tableType = ERROR_TABLE;
440 if (priority == PRIORITY_CT_RULE || priority == PRIORITY_CT_DROP_RULE) {
441 tableType = CT_TABLE;
442 } else if (priority == PRIORITY_CT_HOOK_RULE) {
443 tableType = ACL_TABLE;
444 } else {
445 log.error("Cannot an appropriate table for the conn track rule.");
446 }
447
448 osFlowRuleService.setRule(
449 appId,
450 deviceId,
451 selector,
452 tb.build(),
453 priority,
454 tableType,
455 install);
456 }
457
458 /**
sangho6a9ff0d2017-03-27 11:23:37 +0900459 * Returns a set of host IP addresses engaged with supplied security group ID.
460 * It only searches a VM in the same tenant boundary.
461 *
Jian Lia70fdb602018-11-05 01:32:22 +0900462 * @param srcPort openstack port
sangho6a9ff0d2017-03-27 11:23:37 +0900463 * @param sgId security group id
464 * @return set of ip addresses
465 */
Jian Lia70fdb602018-11-05 01:32:22 +0900466 private Set<InstancePort> getRemoteInstPorts(Port srcPort,
Jian Li2b9838c2018-10-28 17:09:42 +0900467 String sgId, boolean install) {
sangho6a9ff0d2017-03-27 11:23:37 +0900468 Set<InstancePort> remoteInstPorts;
469
Jian Liac30e272018-10-18 23:08:03 +0900470 Set<Port> removedPorts = Sets.newConcurrentHashSet();
471
472 if (!install) {
473 removedPorts = new HashSet<>(removedOsPortStore.asJavaMap().values());
474 }
475
476 remoteInstPorts = Sets.union(osNetService.ports(), removedPorts).stream()
Jian Lia70fdb602018-11-05 01:32:22 +0900477 .filter(port -> !port.getId().equals(srcPort.getId()))
478 .filter(port -> port.getTenantId().equals(srcPort.getTenantId()))
sangho6a9ff0d2017-03-27 11:23:37 +0900479 .filter(port -> port.getSecurityGroups().contains(sgId))
Jian Lia70fdb602018-11-05 01:32:22 +0900480 .filter(port -> port.getNetworkId().equals(srcPort.getNetworkId()))
sangho6a9ff0d2017-03-27 11:23:37 +0900481 .map(port -> instancePortService.instancePort(port.getId()))
482 .filter(instPort -> instPort != null && instPort.ipAddress() != null)
483 .collect(Collectors.toSet());
484
485 return Collections.unmodifiableSet(remoteInstPorts);
486 }
487
sangho2e97be02017-07-03 18:18:27 +0900488 private Set<TrafficSelector> buildSelectors(SecurityGroupRule sgRule,
489 Ip4Address vmIp,
Jian Lie8b28db2018-10-17 14:04:09 +0900490 IpPrefix remoteIp,
491 Port port) {
Jian Li2b9838c2018-10-28 17:09:42 +0900492 if (remoteIp != null && remoteIp.equals(IpPrefix.valueOf(vmIp, VM_IP_PREFIX))) {
sangho2e97be02017-07-03 18:18:27 +0900493 // do nothing if the remote IP is my IP
494 return null;
495 }
496
497 Set<TrafficSelector> selectorSet = Sets.newHashSet();
498
499 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
Jian Lie8b28db2018-10-17 14:04:09 +0900500 buildMatches(sBuilder, sgRule, vmIp, remoteIp, port);
sangho2e97be02017-07-03 18:18:27 +0900501
502 if (sgRule.getPortRangeMax() != null && sgRule.getPortRangeMin() != null &&
503 sgRule.getPortRangeMin() < sgRule.getPortRangeMax()) {
Jian Libcc42282018-09-13 20:59:34 +0900504 Map<TpPort, TpPort> portRangeMatchMap =
505 buildPortRangeMatches(sgRule.getPortRangeMin(),
Jian Li28ec77f2018-10-31 07:07:25 +0900506 sgRule.getPortRangeMax());
Jian Li2b9838c2018-10-28 17:09:42 +0900507 portRangeMatchMap.forEach((key, value) -> {
sangho2e97be02017-07-03 18:18:27 +0900508
Jian Li2b9838c2018-10-28 17:09:42 +0900509 if (sgRule.getProtocol().toUpperCase().equals(PROTO_TCP)) {
510 if (sgRule.getDirection().toUpperCase().equals(EGRESS)) {
511 sBuilder.matchTcpSrcMasked(key, value);
512 } else {
513 sBuilder.matchTcpDstMasked(key, value);
Jian Libcc42282018-09-13 20:59:34 +0900514 }
Jian Li2b9838c2018-10-28 17:09:42 +0900515 } else if (sgRule.getProtocol().toUpperCase().equals(PROTO_UDP)) {
516 if (sgRule.getDirection().toUpperCase().equals(EGRESS)) {
517 sBuilder.matchUdpSrcMasked(key, value);
518 } else {
519 sBuilder.matchUdpDstMasked(key, value);
520 }
521 }
522
523 selectorSet.add(sBuilder.build());
524 });
sangho2e97be02017-07-03 18:18:27 +0900525 } else {
526 selectorSet.add(sBuilder.build());
527 }
528
529 return selectorSet;
530 }
531
Jian Libcc42282018-09-13 20:59:34 +0900532 private void buildMatches(TrafficSelector.Builder sBuilder,
533 SecurityGroupRule sgRule,
Jian Lie8b28db2018-10-17 14:04:09 +0900534 Ip4Address vmIp, IpPrefix remoteIp, Port port) {
535 buildTunnelId(sBuilder, port);
sangho6a9ff0d2017-03-27 11:23:37 +0900536 buildMatchEthType(sBuilder, sgRule.getEtherType());
537 buildMatchDirection(sBuilder, sgRule.getDirection(), vmIp);
538 buildMatchProto(sBuilder, sgRule.getProtocol());
539 buildMatchPort(sBuilder, sgRule.getProtocol(), sgRule.getDirection(),
sangho2e97be02017-07-03 18:18:27 +0900540 sgRule.getPortRangeMin() == null ? 0 : sgRule.getPortRangeMin(),
541 sgRule.getPortRangeMax() == null ? 0 : sgRule.getPortRangeMax());
sangho6a9ff0d2017-03-27 11:23:37 +0900542 buildMatchRemoteIp(sBuilder, remoteIp, sgRule.getDirection());
sangho6a9ff0d2017-03-27 11:23:37 +0900543 }
544
Jian Lie8b28db2018-10-17 14:04:09 +0900545 private void buildTunnelId(TrafficSelector.Builder sBuilder, Port port) {
546 String segId = osNetService.segmentId(port.getNetworkId());
547 String netType = osNetService.networkType(port.getNetworkId());
548
549 if (VLAN.equals(netType)) {
550 sBuilder.matchVlanId(VlanId.vlanId(segId));
551 } else if (VXLAN.equals(netType)) {
552 sBuilder.matchTunnelId(Long.valueOf(segId));
Jian Li28ec77f2018-10-31 07:07:25 +0900553 } else {
554 log.warn("Cannot tag the VID due to lack of support of virtual network type {}", netType);
Jian Lie8b28db2018-10-17 14:04:09 +0900555 }
556 }
557
sangho6a9ff0d2017-03-27 11:23:37 +0900558 private void buildMatchDirection(TrafficSelector.Builder sBuilder,
559 String direction,
560 Ip4Address vmIp) {
561 if (direction.toUpperCase().equals(EGRESS)) {
Jian Li2b9838c2018-10-28 17:09:42 +0900562 sBuilder.matchIPSrc(IpPrefix.valueOf(vmIp, VM_IP_PREFIX));
sangho6a9ff0d2017-03-27 11:23:37 +0900563 } else {
Jian Li2b9838c2018-10-28 17:09:42 +0900564 sBuilder.matchIPDst(IpPrefix.valueOf(vmIp, VM_IP_PREFIX));
sangho6a9ff0d2017-03-27 11:23:37 +0900565 }
566 }
567
568 private void buildMatchEthType(TrafficSelector.Builder sBuilder, String etherType) {
569 // Either IpSrc or IpDst (or both) is set by default, and we need to set EthType as IPv4.
570 sBuilder.matchEthType(Ethernet.TYPE_IPV4);
571 if (etherType != null && !Objects.equals(etherType, "null") &&
572 !etherType.toUpperCase().equals(ETHTYPE_IPV4)) {
573 log.debug("EthType {} is not supported yet in Security Group", etherType);
574 }
575 }
576
Jian Libcc42282018-09-13 20:59:34 +0900577 private void buildMatchRemoteIp(TrafficSelector.Builder sBuilder,
578 IpPrefix remoteIpPrefix, String direction) {
579 if (remoteIpPrefix != null &&
580 !remoteIpPrefix.getIp4Prefix().equals(IP_PREFIX_ANY)) {
sangho6a9ff0d2017-03-27 11:23:37 +0900581 if (direction.toUpperCase().equals(EGRESS)) {
582 sBuilder.matchIPDst(remoteIpPrefix);
583 } else {
584 sBuilder.matchIPSrc(remoteIpPrefix);
585 }
586 }
587 }
588
589 private void buildMatchProto(TrafficSelector.Builder sBuilder, String protocol) {
590 if (protocol != null) {
591 switch (protocol.toUpperCase()) {
592 case PROTO_ICMP:
593 sBuilder.matchIPProtocol(IPv4.PROTOCOL_ICMP);
594 break;
595 case PROTO_TCP:
596 sBuilder.matchIPProtocol(IPv4.PROTOCOL_TCP);
597 break;
598 case PROTO_UDP:
599 sBuilder.matchIPProtocol(IPv4.PROTOCOL_UDP);
600 break;
601 default:
602 }
603 }
604 }
605
Jian Libcc42282018-09-13 20:59:34 +0900606 private void buildMatchPort(TrafficSelector.Builder sBuilder,
607 String protocol, String direction,
sangho6a9ff0d2017-03-27 11:23:37 +0900608 int portMin, int portMax) {
609 if (portMin > 0 && portMax > 0 && portMin == portMax) {
610 if (protocol.toUpperCase().equals(PROTO_TCP)) {
611 if (direction.toUpperCase().equals(EGRESS)) {
612 sBuilder.matchTcpSrc(TpPort.tpPort(portMax));
613 } else {
614 sBuilder.matchTcpDst(TpPort.tpPort(portMax));
615 }
616 } else if (protocol.toUpperCase().equals(PROTO_UDP)) {
617 if (direction.toUpperCase().equals(EGRESS)) {
618 sBuilder.matchUdpSrc(TpPort.tpPort(portMax));
619 } else {
620 sBuilder.matchUdpDst(TpPort.tpPort(portMax));
621 }
622 }
623 }
624 }
625
sangho0248ca22017-05-31 13:22:47 +0900626 private void resetSecurityGroupRules() {
627
628 if (useSecurityGroup) {
Jian Lib6969502018-10-30 20:38:07 +0900629 osNodeService.completeNodes(COMPUTE).forEach(node -> {
630 osFlowRuleService.setUpTableMissEntry(node.intgBridge(), ACL_TABLE);
631 initializeConnTrackTable(node.intgBridge(), true);
632 });
633
sangho0248ca22017-05-31 13:22:47 +0900634 securityGroupService.securityGroups().forEach(securityGroup ->
635 securityGroup.getRules().forEach(this::securityGroupRuleAdded));
636 } else {
Jian Lib6969502018-10-30 20:38:07 +0900637 osNodeService.completeNodes(COMPUTE).forEach(node -> {
638 osFlowRuleService.connectTables(node.intgBridge(), ACL_TABLE, JUMP_TABLE);
639 initializeConnTrackTable(node.intgBridge(), false);
640 });
641
sangho0248ca22017-05-31 13:22:47 +0900642 securityGroupService.securityGroups().forEach(securityGroup ->
643 securityGroup.getRules().forEach(this::securityGroupRuleRemoved));
644 }
645
Jian Libcc42282018-09-13 20:59:34 +0900646 log.info("Reset security group info " +
Jian Li28ec77f2018-10-31 07:07:25 +0900647 (useSecurityGroup ? " with " : " without") + " Security Group");
sangho0248ca22017-05-31 13:22:47 +0900648 }
649
650 private void securityGroupRuleAdded(SecurityGroupRule sgRule) {
651 osNetService.ports().stream()
Jian Libcc42282018-09-13 20:59:34 +0900652 .filter(port -> port.getSecurityGroups()
Jian Li28ec77f2018-10-31 07:07:25 +0900653 .contains(sgRule.getSecurityGroupId()))
sangho0248ca22017-05-31 13:22:47 +0900654 .forEach(port -> {
655 updateSecurityGroupRule(
656 instancePortService.instancePort(port.getId()),
657 port, sgRule, true);
658 log.debug("Applied security group rule {} to port {}",
659 sgRule.getId(), port.getId());
660 });
661 }
662
663 private void securityGroupRuleRemoved(SecurityGroupRule sgRule) {
Jian Liac30e272018-10-18 23:08:03 +0900664 Set<Port> removedPorts = new HashSet<>(removedOsPortStore.asJavaMap().values());
665
666 Sets.union(osNetService.ports(), removedPorts).stream()
Jian Libcc42282018-09-13 20:59:34 +0900667 .filter(port -> port.getSecurityGroups()
Jian Li28ec77f2018-10-31 07:07:25 +0900668 .contains(sgRule.getSecurityGroupId()))
sangho0248ca22017-05-31 13:22:47 +0900669 .forEach(port -> {
670 updateSecurityGroupRule(
671 instancePortService.instancePort(port.getId()),
672 port, sgRule, false);
673 log.debug("Removed security group rule {} from port {}",
674 sgRule.getId(), port.getId());
675 });
676 }
677
sangho2e97be02017-07-03 18:18:27 +0900678 private int binLower(String binStr, int bits) {
Jian Li2b9838c2018-10-28 17:09:42 +0900679 StringBuilder outBin = new StringBuilder(binStr.substring(0, 16 - bits));
sangho2e97be02017-07-03 18:18:27 +0900680 for (int i = 0; i < bits; i++) {
Jian Li2b9838c2018-10-28 17:09:42 +0900681 outBin.append("0");
sangho2e97be02017-07-03 18:18:27 +0900682 }
683
Jian Li2b9838c2018-10-28 17:09:42 +0900684 return Integer.parseInt(outBin.toString(), 2);
sangho2e97be02017-07-03 18:18:27 +0900685 }
686
687 private int binHigher(String binStr, int bits) {
Jian Li2b9838c2018-10-28 17:09:42 +0900688 StringBuilder outBin = new StringBuilder(binStr.substring(0, 16 - bits));
sangho2e97be02017-07-03 18:18:27 +0900689 for (int i = 0; i < bits; i++) {
Jian Li2b9838c2018-10-28 17:09:42 +0900690 outBin.append("1");
sangho2e97be02017-07-03 18:18:27 +0900691 }
692
Jian Li2b9838c2018-10-28 17:09:42 +0900693 return Integer.parseInt(outBin.toString(), 2);
sangho2e97be02017-07-03 18:18:27 +0900694 }
695
696 private int testMasks(String binStr, int start, int end) {
697 int mask = 0;
698 for (; mask <= 16; mask++) {
699 int maskStart = binLower(binStr, mask);
700 int maskEnd = binHigher(binStr, mask);
701 if (maskStart < start || maskEnd > end) {
702 return mask - 1;
703 }
704 }
705
706 return mask;
707 }
708
709 private String getMask(int bits) {
710 switch (bits) {
711 case 0: return "ffff";
712 case 1: return "fffe";
713 case 2: return "fffc";
714 case 3: return "fff8";
715 case 4: return "fff0";
716 case 5: return "ffe0";
717 case 6: return "ffc0";
718 case 7: return "ff80";
719 case 8: return "ff00";
720 case 9: return "fe00";
721 case 10: return "fc00";
722 case 11: return "f800";
723 case 12: return "f000";
724 case 13: return "e000";
725 case 14: return "c000";
726 case 15: return "8000";
727 case 16: return "0000";
728 default: return null;
729 }
730 }
731
732 private Map<TpPort, TpPort> buildPortRangeMatches(int portMin, int portMax) {
733
734 boolean processing = true;
735 int start = portMin;
736 Map<TpPort, TpPort> portMaskMap = Maps.newHashMap();
737 while (processing) {
738 String minStr = Integer.toBinaryString(start);
739 String binStrMinPadded = "0000000000000000".substring(minStr.length()) + minStr;
740
741 int mask = testMasks(binStrMinPadded, start, portMax);
742 int maskStart = binLower(binStrMinPadded, mask);
743 int maskEnd = binHigher(binStrMinPadded, mask);
744
745 log.debug("start : {} port/mask = {} / {} ", start, getMask(mask), maskStart);
Jian Libcc42282018-09-13 20:59:34 +0900746 portMaskMap.put(TpPort.tpPort(maskStart), TpPort.tpPort(
747 Integer.parseInt(Objects.requireNonNull(getMask(mask)), 16)));
sangho2e97be02017-07-03 18:18:27 +0900748
749 start = maskEnd + 1;
750 if (start > portMax) {
751 processing = false;
752 }
753 }
754
755 return portMaskMap;
756 }
757
sangho6a9ff0d2017-03-27 11:23:37 +0900758 private class InternalInstancePortListener implements InstancePortListener {
759
760 @Override
761 public boolean isRelevant(InstancePortEvent event) {
Jian Li2b9838c2018-10-28 17:09:42 +0900762 return useSecurityGroup &&
763 mastershipService.isLocalMaster(event.subject().deviceId());
sangho6a9ff0d2017-03-27 11:23:37 +0900764 }
765
766 @Override
767 public void event(InstancePortEvent event) {
768 InstancePort instPort = event.subject();
769 switch (event.type()) {
Jian Liec5c32b2018-07-13 14:28:58 +0900770 case OPENSTACK_INSTANCE_PORT_UPDATED:
Jian Lie8b28db2018-10-17 14:04:09 +0900771 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Liac30e272018-10-18 23:08:03 +0900772 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
773 installSecurityGroupRules(event, instPort);
774 break;
775 case OPENSTACK_INSTANCE_PORT_VANISHED:
776 Port osPort = removedOsPortStore.asJavaMap().get(instPort.portId());
777 eventExecutor.execute(() ->
778 setSecurityGroupRules(instPort, osPort, false)
779 );
780 removedOsPortStore.remove(instPort.portId());
sangho6a9ff0d2017-03-27 11:23:37 +0900781 break;
Jian Lib8cdcc12018-10-23 01:53:10 +0900782 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
783 InstancePort revisedInstPort = swapStaleLocation(instPort);
784 Port port = osNetService.port(instPort.portId());
785 eventExecutor.execute(() ->
786 setSecurityGroupRules(revisedInstPort, port, false));
sangho6a9ff0d2017-03-27 11:23:37 +0900787 break;
sangho6a9ff0d2017-03-27 11:23:37 +0900788 default:
789 break;
790 }
791 }
Jian Liac30e272018-10-18 23:08:03 +0900792
793 private void installSecurityGroupRules(InstancePortEvent event,
794 InstancePort instPort) {
795 log.debug("Instance port detected/updated MAC:{} IP:{}",
796 instPort.macAddress(),
797 instPort.ipAddress());
Jian Li2b9838c2018-10-28 17:09:42 +0900798 eventExecutor.execute(() ->
799 setSecurityGroupRules(instPort,
800 osNetService.port(event.subject().portId()), true));
Jian Liac30e272018-10-18 23:08:03 +0900801 }
sangho6a9ff0d2017-03-27 11:23:37 +0900802 }
803
804 private class InternalOpenstackPortListener implements OpenstackNetworkListener {
805
806 @Override
807 public boolean isRelevant(OpenstackNetworkEvent event) {
sanghoshinbbeb31a2018-09-11 17:01:01 +0800808 if (event.port() == null || Strings.isNullOrEmpty(event.port().getId())) {
sangho6a9ff0d2017-03-27 11:23:37 +0900809 return false;
810 }
Jian Libcc42282018-09-13 20:59:34 +0900811
812 InstancePort instPort = instancePortService.instancePort(event.port().getId());
813
814 if (instPort == null) {
815 return false;
816 }
817
818 return useSecurityGroup && mastershipService.isLocalMaster(instPort.deviceId());
819 }
820
821 @Override
822 public void event(OpenstackNetworkEvent event) {
823 log.debug("openstack port event received {}", event);
824 Port osPort = event.port();
Jian Libcc42282018-09-13 20:59:34 +0900825
826 switch (event.type()) {
827 case OPENSTACK_PORT_PRE_REMOVE:
Jian Liac30e272018-10-18 23:08:03 +0900828 removedOsPortStore.put(osPort.getId(), osPort);
Jian Libcc42282018-09-13 20:59:34 +0900829 break;
830 default:
831 // do nothing for the other events
832 break;
833 }
834 }
835 }
836
Jian Li2b9838c2018-10-28 17:09:42 +0900837 private class InternalOpenstackNetworkListener
Jian Li28ec77f2018-10-31 07:07:25 +0900838 implements OpenstackNetworkListener {
Jian Libcc42282018-09-13 20:59:34 +0900839
840 @Override
841 public boolean isRelevant(OpenstackNetworkEvent event) {
842 if (event.port() == null || Strings.isNullOrEmpty(event.port().getId())) {
843 return false;
844 }
Jian Li2b9838c2018-10-28 17:09:42 +0900845
Hyunsun Moonae51e732017-04-25 17:46:21 +0900846 if (event.securityGroupId() == null ||
847 securityGroupService.securityGroup(event.securityGroupId()) == null) {
848 return false;
849 }
Jian Li2b9838c2018-10-28 17:09:42 +0900850
851 InstancePort instPort = instancePortService.instancePort(event.port().getId());
852
853 if (instPort == null) {
Hyunsun Moonae51e732017-04-25 17:46:21 +0900854 return false;
855 }
Jian Li2b9838c2018-10-28 17:09:42 +0900856
857 return useSecurityGroup && mastershipService.isLocalMaster(instPort.deviceId());
sangho6a9ff0d2017-03-27 11:23:37 +0900858 }
859
860 @Override
861 public void event(OpenstackNetworkEvent event) {
sanghoshinbbeb31a2018-09-11 17:01:01 +0800862 log.debug("security group event received {}", event);
Hyunsun Moonae51e732017-04-25 17:46:21 +0900863 Port osPort = event.port();
864 InstancePort instPort = instancePortService.instancePort(osPort.getId());
865 SecurityGroup osSg = securityGroupService.securityGroup(event.securityGroupId());
866
sangho6a9ff0d2017-03-27 11:23:37 +0900867 switch (event.type()) {
Hyunsun Moonae51e732017-04-25 17:46:21 +0900868 case OPENSTACK_PORT_SECURITY_GROUP_ADDED:
869 eventExecutor.execute(() -> {
870 osSg.getRules().forEach(sgRule -> {
871 updateSecurityGroupRule(instPort, osPort, sgRule, true);
872 });
873 log.info("Added security group {} to port {}",
874 event.securityGroupId(), event.port().getId());
875 });
sangho6a9ff0d2017-03-27 11:23:37 +0900876 break;
Hyunsun Moonae51e732017-04-25 17:46:21 +0900877 case OPENSTACK_PORT_SECURITY_GROUP_REMOVED:
878 eventExecutor.execute(() -> {
879 osSg.getRules().forEach(sgRule -> {
880 updateSecurityGroupRule(instPort, osPort, sgRule, false);
881 });
882 log.info("Removed security group {} from port {}",
883 event.securityGroupId(), event.port().getId());
884 });
sangho6a9ff0d2017-03-27 11:23:37 +0900885 break;
886 default:
Hyunsun Moonae51e732017-04-25 17:46:21 +0900887 // do nothing for the other events
sangho6a9ff0d2017-03-27 11:23:37 +0900888 break;
889 }
890 }
sangho6a9ff0d2017-03-27 11:23:37 +0900891 }
892
Jian Li2b9838c2018-10-28 17:09:42 +0900893 private class InternalSecurityGroupListener
Jian Li28ec77f2018-10-31 07:07:25 +0900894 implements OpenstackSecurityGroupListener {
sangho6a9ff0d2017-03-27 11:23:37 +0900895
896 @Override
sangho0248ca22017-05-31 13:22:47 +0900897 public boolean isRelevant(OpenstackSecurityGroupEvent event) {
Jian Liac30e272018-10-18 23:08:03 +0900898 // do not allow to proceed without leadership
899 NodeId leader = leadershipService.getLeader(appId.name());
900 if (!Objects.equals(localNodeId, leader)) {
901 return false;
902 }
Jian Libcc42282018-09-13 20:59:34 +0900903 return useSecurityGroup;
sangho0248ca22017-05-31 13:22:47 +0900904 }
905
906 @Override
sangho6a9ff0d2017-03-27 11:23:37 +0900907 public void event(OpenstackSecurityGroupEvent event) {
908 switch (event.type()) {
sangho6a9ff0d2017-03-27 11:23:37 +0900909 case OPENSTACK_SECURITY_GROUP_RULE_CREATED:
Jian Li2b9838c2018-10-28 17:09:42 +0900910 SecurityGroupRule sgRuleToAdd = event.securityGroupRule();
sangho6a9ff0d2017-03-27 11:23:37 +0900911 eventExecutor.execute(() -> {
Jian Li2b9838c2018-10-28 17:09:42 +0900912 securityGroupRuleAdded(sgRuleToAdd);
Hyunsun Moonae51e732017-04-25 17:46:21 +0900913 log.info("Applied new security group rule {} to ports",
Jian Li2b9838c2018-10-28 17:09:42 +0900914 sgRuleToAdd.getId());
sangho6a9ff0d2017-03-27 11:23:37 +0900915 });
916 break;
917
918 case OPENSTACK_SECURITY_GROUP_RULE_REMOVED:
Jian Li2b9838c2018-10-28 17:09:42 +0900919 SecurityGroupRule sgRuleToRemove = event.securityGroupRule();
sangho6a9ff0d2017-03-27 11:23:37 +0900920 eventExecutor.execute(() -> {
Jian Li2b9838c2018-10-28 17:09:42 +0900921 securityGroupRuleRemoved(sgRuleToRemove);
Hyunsun Moonae51e732017-04-25 17:46:21 +0900922 log.info("Removed security group rule {} from ports",
Jian Li2b9838c2018-10-28 17:09:42 +0900923 sgRuleToRemove.getId());
sangho6a9ff0d2017-03-27 11:23:37 +0900924 });
925 break;
Hyunsun Moonae51e732017-04-25 17:46:21 +0900926 case OPENSTACK_SECURITY_GROUP_REMOVED:
Jian Li9d35bd62018-10-13 01:43:24 +0900927 case OPENSTACK_SECURITY_GROUP_CREATED:
sangho6a9ff0d2017-03-27 11:23:37 +0900928 default:
Hyunsun Moonae51e732017-04-25 17:46:21 +0900929 // do nothing
930 break;
sangho6a9ff0d2017-03-27 11:23:37 +0900931 }
932 }
sangho6a9ff0d2017-03-27 11:23:37 +0900933 }
sangho1aaa7882017-05-31 13:22:47 +0900934
935 private class InternalNodeListener implements OpenstackNodeListener {
936
937 @Override
938 public boolean isRelevant(OpenstackNodeEvent event) {
939 // do not allow to proceed without leadership
940 NodeId leader = leadershipService.getLeader(appId.name());
941 if (!Objects.equals(localNodeId, leader)) {
942 return false;
943 }
944 return event.subject().type() == COMPUTE;
945 }
946
947 @Override
948 public void event(OpenstackNodeEvent event) {
sangho1aaa7882017-05-31 13:22:47 +0900949 switch (event.type()) {
950 case OPENSTACK_NODE_COMPLETE:
Jian Lib6969502018-10-30 20:38:07 +0900951 resetSecurityGroupRules();
sangho1aaa7882017-05-31 13:22:47 +0900952 break;
953 case OPENSTACK_NODE_CREATED:
954 case OPENSTACK_NODE_REMOVED:
955 case OPENSTACK_NODE_UPDATED:
956 case OPENSTACK_NODE_INCOMPLETE:
957 default:
958 break;
959 }
960 }
961 }
Jian Libcc42282018-09-13 20:59:34 +0900962}