blob: 83f75aa5e12e02662dc116c016cc60828edb95fe [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.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;
Jian Lie8b28db2018-10-17 14:04:09 +090035import org.onlab.packet.VlanId;
Jian Liac30e272018-10-18 23:08:03 +090036import org.onlab.util.KryoNamespace;
sangho0248ca22017-05-31 13:22:47 +090037import org.onlab.util.Tools;
38import org.onosproject.cfg.ComponentConfigService;
sangho1aaa7882017-05-31 13:22:47 +090039import org.onosproject.cluster.ClusterService;
40import org.onosproject.cluster.LeadershipService;
41import org.onosproject.cluster.NodeId;
sangho6a9ff0d2017-03-27 11:23:37 +090042import org.onosproject.core.ApplicationId;
43import org.onosproject.core.CoreService;
44import org.onosproject.mastership.MastershipService;
sangho1aaa7882017-05-31 13:22:47 +090045import org.onosproject.net.DeviceId;
46import org.onosproject.net.driver.DriverService;
sangho6a9ff0d2017-03-27 11:23:37 +090047import org.onosproject.net.flow.DefaultTrafficSelector;
48import org.onosproject.net.flow.DefaultTrafficTreatment;
49import org.onosproject.net.flow.TrafficSelector;
sangho1aaa7882017-05-31 13:22:47 +090050import org.onosproject.net.flow.TrafficTreatment;
51import org.onosproject.net.flow.criteria.ExtensionSelector;
Jian Li28ec77f2018-10-31 07:07:25 +090052import org.onosproject.net.flow.instructions.ExtensionTreatment;
sangho6a9ff0d2017-03-27 11:23:37 +090053import org.onosproject.openstacknetworking.api.InstancePort;
Jian Li9d35bd62018-10-13 01:43:24 +090054import org.onosproject.openstacknetworking.api.InstancePortAdminService;
sangho6a9ff0d2017-03-27 11:23:37 +090055import org.onosproject.openstacknetworking.api.InstancePortEvent;
56import org.onosproject.openstacknetworking.api.InstancePortListener;
sanghodc375372017-06-08 10:41:30 +090057import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
sangho6a9ff0d2017-03-27 11:23:37 +090058import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
59import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
60import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
61import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupEvent;
62import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupListener;
63import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupService;
Jian Li26949762018-03-30 15:46:37 +090064import org.onosproject.openstacknetworking.util.RulePopulatorUtil;
sangho1aaa7882017-05-31 13:22:47 +090065import org.onosproject.openstacknode.api.OpenstackNodeEvent;
66import org.onosproject.openstacknode.api.OpenstackNodeListener;
sangho3dd2a8b2017-07-19 15:54:31 +090067import org.onosproject.openstacknode.api.OpenstackNodeService;
Jian Liac30e272018-10-18 23:08:03 +090068import org.onosproject.store.serializers.KryoNamespaces;
69import org.onosproject.store.service.ConsistentMap;
70import org.onosproject.store.service.Serializer;
71import org.onosproject.store.service.StorageService;
sangho6a9ff0d2017-03-27 11:23:37 +090072import org.openstack4j.model.network.Port;
73import org.openstack4j.model.network.SecurityGroup;
74import org.openstack4j.model.network.SecurityGroupRule;
Jian Liac30e272018-10-18 23:08:03 +090075import org.openstack4j.model.network.State;
76import org.openstack4j.openstack.networking.domain.NeutronAllowedAddressPair;
77import org.openstack4j.openstack.networking.domain.NeutronExtraDhcpOptCreate;
78import org.openstack4j.openstack.networking.domain.NeutronIP;
79import org.openstack4j.openstack.networking.domain.NeutronPort;
sangho6a9ff0d2017-03-27 11:23:37 +090080import org.openstack4j.openstack.networking.domain.NeutronSecurityGroupRule;
sangho0248ca22017-05-31 13:22:47 +090081import org.osgi.service.component.ComponentContext;
sangho6a9ff0d2017-03-27 11:23:37 +090082import org.slf4j.Logger;
83
sangho6a9ff0d2017-03-27 11:23:37 +090084import java.util.Collections;
sangho0248ca22017-05-31 13:22:47 +090085import java.util.Dictionary;
Jian Liac30e272018-10-18 23:08:03 +090086import java.util.HashSet;
87import java.util.LinkedHashMap;
sangho2e97be02017-07-03 18:18:27 +090088import java.util.Map;
sangho6a9ff0d2017-03-27 11:23:37 +090089import java.util.Objects;
90import java.util.Set;
91import java.util.concurrent.ExecutorService;
92import java.util.stream.Collectors;
93
94import static java.util.concurrent.Executors.newSingleThreadExecutor;
95import static org.onlab.util.Tools.groupedThreads;
sanghodc375372017-06-08 10:41:30 +090096import static org.onosproject.openstacknetworking.api.Constants.ACL_TABLE;
sangho1aaa7882017-05-31 13:22:47 +090097import static org.onosproject.openstacknetworking.api.Constants.CT_TABLE;
98import static org.onosproject.openstacknetworking.api.Constants.ERROR_TABLE;
Jian Li9d35bd62018-10-13 01:43:24 +090099import static org.onosproject.openstacknetworking.api.Constants.JUMP_TABLE;
sangho6a9ff0d2017-03-27 11:23:37 +0900100import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
101import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ACL_RULE;
sangho1aaa7882017-05-31 13:22:47 +0900102import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_CT_DROP_RULE;
103import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_CT_HOOK_RULE;
104import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_CT_RULE;
Jian Lib8cdcc12018-10-23 01:53:10 +0900105import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
Jian Libcc42282018-09-13 20:59:34 +0900106import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.computeCtMaskFlag;
107import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.computeCtStateFlag;
108import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.niciraConnTrackTreatmentBuilder;
sangho1aaa7882017-05-31 13:22:47 +0900109import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
sangho6a9ff0d2017-03-27 11:23:37 +0900110import static org.slf4j.LoggerFactory.getLogger;
111
112/**
113 * Populates flow rules to handle OpenStack SecurityGroups.
114 */
115@Component(immediate = true)
116public class OpenstackSecurityGroupHandler {
117
118 private final Logger log = getLogger(getClass());
119
sangho0248ca22017-05-31 13:22:47 +0900120 private static final boolean USE_SECURITY_GROUP = false;
121
Jian Li2b9838c2018-10-28 17:09:42 +0900122 private static final int VM_IP_PREFIX = 32;
123
sangho0248ca22017-05-31 13:22:47 +0900124 @Property(name = "useSecurityGroup", boolValue = USE_SECURITY_GROUP,
125 label = "Apply OpenStack security group rule for VM traffic")
126 private boolean useSecurityGroup = USE_SECURITY_GROUP;
127
sangho6a9ff0d2017-03-27 11:23:37 +0900128 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
129 protected CoreService coreService;
130
131 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Li9d35bd62018-10-13 01:43:24 +0900132 protected InstancePortAdminService instancePortService;
sangho6a9ff0d2017-03-27 11:23:37 +0900133
134 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
135 protected MastershipService mastershipService;
136
137 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moonae51e732017-04-25 17:46:21 +0900138 protected OpenstackNetworkService osNetService;
sangho6a9ff0d2017-03-27 11:23:37 +0900139
140 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
141 protected OpenstackSecurityGroupService securityGroupService;
142
143 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sanghodc375372017-06-08 10:41:30 +0900144 protected OpenstackFlowRuleService osFlowRuleService;
sangho6a9ff0d2017-03-27 11:23:37 +0900145
sangho0248ca22017-05-31 13:22:47 +0900146 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
147 protected ComponentConfigService configService;
148
sangho3dd2a8b2017-07-19 15:54:31 +0900149 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
150 protected OpenstackNodeService osNodeService;
151
sanghoe6457a32017-08-24 14:31:19 +0900152 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho1aaa7882017-05-31 13:22:47 +0900153 protected DriverService driverService;
154
155 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
156 protected LeadershipService leadershipService;
157
158 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
159 protected ClusterService clusterService;
160
Jian Li9d35bd62018-10-13 01:43:24 +0900161 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Liac30e272018-10-18 23:08:03 +0900162 protected StorageService storageService;
163
164 private static final KryoNamespace SERIALIZER_PORT = KryoNamespace.newBuilder()
165 .register(KryoNamespaces.API)
166 .register(Port.class)
167 .register(NeutronPort.class)
168 .register(NeutronIP.class)
169 .register(State.class)
170 .register(NeutronAllowedAddressPair.class)
171 .register(NeutronExtraDhcpOptCreate.class)
172 .register(LinkedHashMap.class)
173 .build();
Jian Li9d35bd62018-10-13 01:43:24 +0900174
Jian Libcc42282018-09-13 20:59:34 +0900175 private final InstancePortListener instancePortListener =
Jian Lia70fdb602018-11-05 01:32:22 +0900176 new InternalInstancePortListener();
Jian Libcc42282018-09-13 20:59:34 +0900177 private final OpenstackNetworkListener osNetworkListener =
Jian Lia70fdb602018-11-05 01:32:22 +0900178 new InternalOpenstackNetworkListener();
Jian Libcc42282018-09-13 20:59:34 +0900179 private final OpenstackNetworkListener osPortListener =
Jian Lia70fdb602018-11-05 01:32:22 +0900180 new InternalOpenstackPortListener();
Jian Libcc42282018-09-13 20:59:34 +0900181 private final OpenstackSecurityGroupListener securityGroupListener =
Jian Lia70fdb602018-11-05 01:32:22 +0900182 new InternalSecurityGroupListener();
sangho1aaa7882017-05-31 13:22:47 +0900183 private final OpenstackNodeListener osNodeListener = new InternalNodeListener();
Jian Liac30e272018-10-18 23:08:03 +0900184
185 private ConsistentMap<String, Port> removedOsPortStore;
186
sangho6a9ff0d2017-03-27 11:23:37 +0900187 private ApplicationId appId;
sangho1aaa7882017-05-31 13:22:47 +0900188 private NodeId localNodeId;
sangho6a9ff0d2017-03-27 11:23:37 +0900189
190 private final ExecutorService eventExecutor = newSingleThreadExecutor(
191 groupedThreads(this.getClass().getSimpleName(), "event-handler"));
192
193 private static final String PROTO_ICMP = "ICMP";
194 private static final String PROTO_TCP = "TCP";
195 private static final String PROTO_UDP = "UDP";
196 private static final String ETHTYPE_IPV4 = "IPV4";
197 private static final String EGRESS = "EGRESS";
198 private static final String INGRESS = "INGRESS";
199 private static final IpPrefix IP_PREFIX_ANY = Ip4Prefix.valueOf("0.0.0.0/0");
200
Jian Lie8b28db2018-10-17 14:04:09 +0900201 private static final String VXLAN = "VXLAN";
202 private static final String VLAN = "VLAN";
203
sangho1aaa7882017-05-31 13:22:47 +0900204 // We expose pipeline structure to SONA application considering removing pipeline soon.
sanghoshinbbeb31a2018-09-11 17:01:01 +0800205 private static final int GOTO_CONNTRACK_TABLE = CT_TABLE;
206 private static final int GOTO_JUMP_TABLE = JUMP_TABLE;
sangho1aaa7882017-05-31 13:22:47 +0900207
208 private static final int CT_COMMIT = 0;
209 private static final int CT_NO_COMMIT = 1;
210 private static final short CT_NO_RECIRC = -1;
211
212 private static final int ACTION_NONE = 0;
213 private static final int ACTION_DROP = -1;
214
sangho6a9ff0d2017-03-27 11:23:37 +0900215 @Activate
216 protected void activate() {
217 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
sangho1aaa7882017-05-31 13:22:47 +0900218 localNodeId = clusterService.getLocalNode().id();
sangho6a9ff0d2017-03-27 11:23:37 +0900219 instancePortService.addListener(instancePortListener);
220 securityGroupService.addListener(securityGroupListener);
Jian Libcc42282018-09-13 20:59:34 +0900221 osNetService.addListener(osPortListener);
222 osNetService.addListener(osNetworkListener);
sangho0248ca22017-05-31 13:22:47 +0900223 configService.registerProperties(getClass());
sangho1aaa7882017-05-31 13:22:47 +0900224 osNodeService.addListener(osNodeListener);
sangho6a9ff0d2017-03-27 11:23:37 +0900225
Jian Liac30e272018-10-18 23:08:03 +0900226 removedOsPortStore = storageService.<String, Port>consistentMapBuilder()
227 .withSerializer(Serializer.using(SERIALIZER_PORT))
228 .withName("openstack-removed-portstore")
229 .withApplicationId(appId)
230 .build();
231
sangho6a9ff0d2017-03-27 11:23:37 +0900232 log.info("Started");
233 }
234
235 @Deactivate
236 protected void deactivate() {
237 instancePortService.removeListener(instancePortListener);
238 securityGroupService.removeListener(securityGroupListener);
Jian Libcc42282018-09-13 20:59:34 +0900239 osNetService.removeListener(osNetworkListener);
240 osNetService.removeListener(osPortListener);
sangho0248ca22017-05-31 13:22:47 +0900241 configService.unregisterProperties(getClass(), false);
sangho1aaa7882017-05-31 13:22:47 +0900242 osNodeService.removeListener(osNodeListener);
sangho6a9ff0d2017-03-27 11:23:37 +0900243 eventExecutor.shutdown();
244
245 log.info("Stopped");
246 }
247
sangho0248ca22017-05-31 13:22:47 +0900248 @Modified
249 protected void modified(ComponentContext context) {
250 Dictionary<?, ?> properties = context.getProperties();
251 Boolean flag;
252
253 flag = Tools.isPropertyEnabled(properties, "useSecurityGroup");
254 if (flag == null) {
255 log.info("useSecurityGroup is not configured, " +
256 "using current value of {}", useSecurityGroup);
257 } else {
258 useSecurityGroup = flag;
259 log.info("Configured. useSecurityGroup is {}",
260 useSecurityGroup ? "enabled" : "disabled");
261 }
262
sanghoe6457a32017-08-24 14:31:19 +0900263 securityGroupService.setSecurityGroupEnabled(useSecurityGroup);
sangho0248ca22017-05-31 13:22:47 +0900264 resetSecurityGroupRules();
265 }
266
sangho1aaa7882017-05-31 13:22:47 +0900267 private void initializeConnTrackTable(DeviceId deviceId, boolean install) {
268
269 //table=1,ip,ct_state=-trk, actions=ct(table:2)
Jian Libcc42282018-09-13 20:59:34 +0900270 long ctState = computeCtStateFlag(false, false, false);
271 long ctMask = computeCtMaskFlag(true, false, false);
sangho1aaa7882017-05-31 13:22:47 +0900272 setConnTrackRule(deviceId, ctState, ctMask, CT_NO_COMMIT, (short) GOTO_CONNTRACK_TABLE,
273 ACTION_NONE, PRIORITY_CT_HOOK_RULE, install);
274
275 //table=2,ip,nw_dst=10.10.0.2,ct_state=+trk+est,action=goto_table:3
Jian Libcc42282018-09-13 20:59:34 +0900276 ctState = computeCtStateFlag(true, false, true);
277 ctMask = computeCtMaskFlag(true, false, true);
sangho1aaa7882017-05-31 13:22:47 +0900278 setConnTrackRule(deviceId, ctState, ctMask, CT_NO_COMMIT, CT_NO_RECIRC,
279 GOTO_JUMP_TABLE, PRIORITY_CT_RULE, install);
280
281 //table=2,ip,nw_dst=10.10.0.2,ct_state=+trk+new,action=drop
Jian Libcc42282018-09-13 20:59:34 +0900282 ctState = computeCtStateFlag(true, true, false);
283 ctMask = computeCtMaskFlag(true, true, false);
sangho1aaa7882017-05-31 13:22:47 +0900284 setConnTrackRule(deviceId, ctState, ctMask, CT_NO_COMMIT, CT_NO_RECIRC,
285 ACTION_DROP, PRIORITY_CT_DROP_RULE, install);
286 }
287
Jian Libcc42282018-09-13 20:59:34 +0900288 private void setSecurityGroupRules(InstancePort instPort,
289 Port port, boolean install) {
Jian Liac30e272018-10-18 23:08:03 +0900290
291 if (!install) {
292 Port rmvPort = removedOsPortStore.asJavaMap().get(instPort.portId());
293 if (port == null && rmvPort == null) {
294 return;
295 }
296
297 if (port == null) {
298 port = rmvPort;
299 }
300 }
301
302 final Port finalPort = port;
303
sangho6a9ff0d2017-03-27 11:23:37 +0900304 port.getSecurityGroups().forEach(sgId -> {
sangho6a9ff0d2017-03-27 11:23:37 +0900305 SecurityGroup sg = securityGroupService.securityGroup(sgId);
306 if (sg == null) {
307 log.error("Security Group Not Found : {}", sgId);
308 return;
309 }
Jian Libcc42282018-09-13 20:59:34 +0900310 sg.getRules().forEach(sgRule ->
Jian Liac30e272018-10-18 23:08:03 +0900311 updateSecurityGroupRule(instPort, finalPort, sgRule, install));
Hyunsun Moonae51e732017-04-25 17:46:21 +0900312 final String action = install ? "Installed " : "Removed ";
313 log.debug(action + "security group rule ID : " + sgId);
sangho6a9ff0d2017-03-27 11:23:37 +0900314 });
315 }
316
Jian Libcc42282018-09-13 20:59:34 +0900317 private void updateSecurityGroupRule(InstancePort instPort, Port port,
318 SecurityGroupRule sgRule, boolean install) {
sangho2e97be02017-07-03 18:18:27 +0900319
Daniel Park3a140592018-06-28 18:33:10 +0900320 if (instPort == null || port == null || sgRule == null) {
321 return;
322 }
323
sangho6a9ff0d2017-03-27 11:23:37 +0900324 if (sgRule.getRemoteGroupId() != null && !sgRule.getRemoteGroupId().isEmpty()) {
Jian Lia70fdb602018-11-05 01:32:22 +0900325 getRemoteInstPorts(port, sgRule.getRemoteGroupId(), install)
Jian Libcc42282018-09-13 20:59:34 +0900326 .forEach(rInstPort -> {
Jian Lie8b28db2018-10-17 14:04:09 +0900327 populateSecurityGroupRule(sgRule, instPort, port,
Jian Libcc42282018-09-13 20:59:34 +0900328 rInstPort.ipAddress().toIpPrefix(), install);
Jian Lie8b28db2018-10-17 14:04:09 +0900329 populateSecurityGroupRule(sgRule, rInstPort, port,
Jian Libcc42282018-09-13 20:59:34 +0900330 instPort.ipAddress().toIpPrefix(), install);
sangho6a9ff0d2017-03-27 11:23:37 +0900331
Jian Libcc42282018-09-13 20:59:34 +0900332 SecurityGroupRule rSgRule =
333 new NeutronSecurityGroupRule
334 .SecurityGroupRuleConcreteBuilder()
Jian Li28ec77f2018-10-31 07:07:25 +0900335 .from(sgRule)
336 .direction(sgRule.getDirection().toUpperCase()
337 .equals(EGRESS) ? INGRESS : EGRESS)
338 .build();
Jian Lie8b28db2018-10-17 14:04:09 +0900339 populateSecurityGroupRule(rSgRule, instPort, port,
Jian Libcc42282018-09-13 20:59:34 +0900340 rInstPort.ipAddress().toIpPrefix(), install);
Jian Lie8b28db2018-10-17 14:04:09 +0900341 populateSecurityGroupRule(rSgRule, rInstPort, port,
Jian Libcc42282018-09-13 20:59:34 +0900342 instPort.ipAddress().toIpPrefix(), install);
343 });
sangho6a9ff0d2017-03-27 11:23:37 +0900344 } else {
Jian Lie8b28db2018-10-17 14:04:09 +0900345 populateSecurityGroupRule(sgRule, instPort, port,
Jian Libcc42282018-09-13 20:59:34 +0900346 sgRule.getRemoteIpPrefix() == null ? IP_PREFIX_ANY :
Jian Li28ec77f2018-10-31 07:07:25 +0900347 IpPrefix.valueOf(sgRule.getRemoteIpPrefix()), install);
sangho6a9ff0d2017-03-27 11:23:37 +0900348 }
349 }
350
Jian Libcc42282018-09-13 20:59:34 +0900351 private void populateSecurityGroupRule(SecurityGroupRule sgRule,
352 InstancePort instPort,
Jian Lie8b28db2018-10-17 14:04:09 +0900353 Port port,
354 IpPrefix remoteIp,
355 boolean install) {
sangho2e97be02017-07-03 18:18:27 +0900356 Set<TrafficSelector> selectors = buildSelectors(sgRule,
Jian Lie8b28db2018-10-17 14:04:09 +0900357 Ip4Address.valueOf(instPort.ipAddress().toInetAddress()), remoteIp, port);
sangho2e97be02017-07-03 18:18:27 +0900358 if (selectors == null || selectors.isEmpty()) {
sangho6a9ff0d2017-03-27 11:23:37 +0900359 return;
360 }
361
Jian Li28ec77f2018-10-31 07:07:25 +0900362 // XXX All egress traffic needs to go through connection tracking module,
363 // which might hurt its performance.
364 ExtensionTreatment ctTreatment =
365 niciraConnTrackTreatmentBuilder(driverService, instPort.deviceId())
366 .commit(true)
367 .build();
368
369 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
370 .extension(ctTreatment, instPort.deviceId())
371 .transition(JUMP_TABLE)
372 .build();
373
Jian Li2b9838c2018-10-28 17:09:42 +0900374 selectors.forEach(selector ->
375 osFlowRuleService.setRule(appId,
Jian Li28ec77f2018-10-31 07:07:25 +0900376 instPort.deviceId(),
377 selector, treatment,
378 PRIORITY_ACL_RULE,
379 ACL_TABLE,
380 install));
sangho6a9ff0d2017-03-27 11:23:37 +0900381 }
382
383 /**
sangho1aaa7882017-05-31 13:22:47 +0900384 * Sets connection tracking rule using OVS extension commands.
Jian Li2b9838c2018-10-28 17:09:42 +0900385 * It is not so graceful, but I don't want to make it more general because
386 * it is going to be used only here.
387 * The following is the usage of the function.
sangho1aaa7882017-05-31 13:22:47 +0900388 *
389 * @param deviceId Device ID
Jian Li2b9838c2018-10-28 17:09:42 +0900390 * @param ctState ctState: please use RulePopulatorUtil.computeCtStateFlag()
391 * to build the value
392 * @param ctMask crMask: please use RulePopulatorUtil.computeCtMaskFlag()
393 * to build the value
sangho1aaa7882017-05-31 13:22:47 +0900394 * @param commit CT_COMMIT for commit action, CT_NO_COMMIT otherwise
Jian Li2b9838c2018-10-28 17:09:42 +0900395 * @param recircTable table number for recirculation after CT actions.
396 * CT_NO_RECIRC with no recirculation
397 * @param action Additional actions. ACTION_DROP, ACTION_NONE,
398 * GOTO_XXX_TABLE are supported.
sangho1aaa7882017-05-31 13:22:47 +0900399 * @param priority priority value for the rule
400 * @param install true for insertion, false for removal
401 */
402 private void setConnTrackRule(DeviceId deviceId, long ctState, long ctMask,
403 int commit, short recircTable,
404 int action, int priority, boolean install) {
405
Jian Libcc42282018-09-13 20:59:34 +0900406 ExtensionSelector esCtSate = RulePopulatorUtil
407 .buildCtExtensionSelector(driverService, deviceId, ctState, ctMask);
sangho1aaa7882017-05-31 13:22:47 +0900408 TrafficSelector selector = DefaultTrafficSelector.builder()
409 .extension(esCtSate, deviceId)
410 .matchEthType(Ethernet.TYPE_IPV4)
411 .build();
412
413 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
414
415 if (commit == CT_COMMIT || recircTable > 0) {
416 RulePopulatorUtil.NiriraConnTrackTreatmentBuilder natTreatmentBuilder =
Jian Libcc42282018-09-13 20:59:34 +0900417 niciraConnTrackTreatmentBuilder(driverService, deviceId);
sangho1aaa7882017-05-31 13:22:47 +0900418 natTreatmentBuilder.natAction(false);
419 if (commit == CT_COMMIT) {
420 natTreatmentBuilder.commit(true);
421 } else {
422 natTreatmentBuilder.commit(false);
423 }
424 if (recircTable > 0) {
425 natTreatmentBuilder.table(recircTable);
426 }
427 tb.extension(natTreatmentBuilder.build(), deviceId);
428 } else if (action == ACTION_DROP) {
429 tb.drop();
430 }
431
sanghoshinbbeb31a2018-09-11 17:01:01 +0800432 if (action != ACTION_NONE && action != ACTION_DROP) {
sangho1aaa7882017-05-31 13:22:47 +0900433 tb.transition(action);
434 }
435
436 int tableType = ERROR_TABLE;
437 if (priority == PRIORITY_CT_RULE || priority == PRIORITY_CT_DROP_RULE) {
438 tableType = CT_TABLE;
439 } else if (priority == PRIORITY_CT_HOOK_RULE) {
440 tableType = ACL_TABLE;
441 } else {
442 log.error("Cannot an appropriate table for the conn track rule.");
443 }
444
445 osFlowRuleService.setRule(
446 appId,
447 deviceId,
448 selector,
449 tb.build(),
450 priority,
451 tableType,
452 install);
453 }
454
455 /**
sangho6a9ff0d2017-03-27 11:23:37 +0900456 * Returns a set of host IP addresses engaged with supplied security group ID.
457 * It only searches a VM in the same tenant boundary.
458 *
Jian Lia70fdb602018-11-05 01:32:22 +0900459 * @param srcPort openstack port
sangho6a9ff0d2017-03-27 11:23:37 +0900460 * @param sgId security group id
461 * @return set of ip addresses
462 */
Jian Lia70fdb602018-11-05 01:32:22 +0900463 private Set<InstancePort> getRemoteInstPorts(Port srcPort,
Jian Li2b9838c2018-10-28 17:09:42 +0900464 String sgId, boolean install) {
sangho6a9ff0d2017-03-27 11:23:37 +0900465 Set<InstancePort> remoteInstPorts;
466
Jian Liac30e272018-10-18 23:08:03 +0900467 Set<Port> removedPorts = Sets.newConcurrentHashSet();
468
469 if (!install) {
470 removedPorts = new HashSet<>(removedOsPortStore.asJavaMap().values());
471 }
472
473 remoteInstPorts = Sets.union(osNetService.ports(), removedPorts).stream()
Jian Lia70fdb602018-11-05 01:32:22 +0900474 .filter(port -> !port.getId().equals(srcPort.getId()))
475 .filter(port -> port.getTenantId().equals(srcPort.getTenantId()))
sangho6a9ff0d2017-03-27 11:23:37 +0900476 .filter(port -> port.getSecurityGroups().contains(sgId))
Jian Lia70fdb602018-11-05 01:32:22 +0900477 .filter(port -> port.getNetworkId().equals(srcPort.getNetworkId()))
sangho6a9ff0d2017-03-27 11:23:37 +0900478 .map(port -> instancePortService.instancePort(port.getId()))
479 .filter(instPort -> instPort != null && instPort.ipAddress() != null)
480 .collect(Collectors.toSet());
481
482 return Collections.unmodifiableSet(remoteInstPorts);
483 }
484
sangho2e97be02017-07-03 18:18:27 +0900485 private Set<TrafficSelector> buildSelectors(SecurityGroupRule sgRule,
486 Ip4Address vmIp,
Jian Lie8b28db2018-10-17 14:04:09 +0900487 IpPrefix remoteIp,
488 Port port) {
Jian Li2b9838c2018-10-28 17:09:42 +0900489 if (remoteIp != null && remoteIp.equals(IpPrefix.valueOf(vmIp, VM_IP_PREFIX))) {
sangho2e97be02017-07-03 18:18:27 +0900490 // do nothing if the remote IP is my IP
491 return null;
492 }
493
494 Set<TrafficSelector> selectorSet = Sets.newHashSet();
495
496 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
Jian Lie8b28db2018-10-17 14:04:09 +0900497 buildMatches(sBuilder, sgRule, vmIp, remoteIp, port);
sangho2e97be02017-07-03 18:18:27 +0900498
499 if (sgRule.getPortRangeMax() != null && sgRule.getPortRangeMin() != null &&
500 sgRule.getPortRangeMin() < sgRule.getPortRangeMax()) {
Jian Libcc42282018-09-13 20:59:34 +0900501 Map<TpPort, TpPort> portRangeMatchMap =
502 buildPortRangeMatches(sgRule.getPortRangeMin(),
Jian Li28ec77f2018-10-31 07:07:25 +0900503 sgRule.getPortRangeMax());
Jian Li2b9838c2018-10-28 17:09:42 +0900504 portRangeMatchMap.forEach((key, value) -> {
sangho2e97be02017-07-03 18:18:27 +0900505
Jian Li2b9838c2018-10-28 17:09:42 +0900506 if (sgRule.getProtocol().toUpperCase().equals(PROTO_TCP)) {
507 if (sgRule.getDirection().toUpperCase().equals(EGRESS)) {
508 sBuilder.matchTcpSrcMasked(key, value);
509 } else {
510 sBuilder.matchTcpDstMasked(key, value);
Jian Libcc42282018-09-13 20:59:34 +0900511 }
Jian Li2b9838c2018-10-28 17:09:42 +0900512 } else if (sgRule.getProtocol().toUpperCase().equals(PROTO_UDP)) {
513 if (sgRule.getDirection().toUpperCase().equals(EGRESS)) {
514 sBuilder.matchUdpSrcMasked(key, value);
515 } else {
516 sBuilder.matchUdpDstMasked(key, value);
517 }
518 }
519
520 selectorSet.add(sBuilder.build());
521 });
sangho2e97be02017-07-03 18:18:27 +0900522 } else {
523 selectorSet.add(sBuilder.build());
524 }
525
526 return selectorSet;
527 }
528
Jian Libcc42282018-09-13 20:59:34 +0900529 private void buildMatches(TrafficSelector.Builder sBuilder,
530 SecurityGroupRule sgRule,
Jian Lie8b28db2018-10-17 14:04:09 +0900531 Ip4Address vmIp, IpPrefix remoteIp, Port port) {
532 buildTunnelId(sBuilder, port);
sangho6a9ff0d2017-03-27 11:23:37 +0900533 buildMatchEthType(sBuilder, sgRule.getEtherType());
534 buildMatchDirection(sBuilder, sgRule.getDirection(), vmIp);
535 buildMatchProto(sBuilder, sgRule.getProtocol());
536 buildMatchPort(sBuilder, sgRule.getProtocol(), sgRule.getDirection(),
sangho2e97be02017-07-03 18:18:27 +0900537 sgRule.getPortRangeMin() == null ? 0 : sgRule.getPortRangeMin(),
538 sgRule.getPortRangeMax() == null ? 0 : sgRule.getPortRangeMax());
sangho6a9ff0d2017-03-27 11:23:37 +0900539 buildMatchRemoteIp(sBuilder, remoteIp, sgRule.getDirection());
sangho6a9ff0d2017-03-27 11:23:37 +0900540 }
541
Jian Lie8b28db2018-10-17 14:04:09 +0900542 private void buildTunnelId(TrafficSelector.Builder sBuilder, Port port) {
543 String segId = osNetService.segmentId(port.getNetworkId());
544 String netType = osNetService.networkType(port.getNetworkId());
545
546 if (VLAN.equals(netType)) {
547 sBuilder.matchVlanId(VlanId.vlanId(segId));
548 } else if (VXLAN.equals(netType)) {
549 sBuilder.matchTunnelId(Long.valueOf(segId));
Jian Li28ec77f2018-10-31 07:07:25 +0900550 } else {
551 log.warn("Cannot tag the VID due to lack of support of virtual network type {}", netType);
Jian Lie8b28db2018-10-17 14:04:09 +0900552 }
553 }
554
sangho6a9ff0d2017-03-27 11:23:37 +0900555 private void buildMatchDirection(TrafficSelector.Builder sBuilder,
556 String direction,
557 Ip4Address vmIp) {
558 if (direction.toUpperCase().equals(EGRESS)) {
Jian Li2b9838c2018-10-28 17:09:42 +0900559 sBuilder.matchIPSrc(IpPrefix.valueOf(vmIp, VM_IP_PREFIX));
sangho6a9ff0d2017-03-27 11:23:37 +0900560 } else {
Jian Li2b9838c2018-10-28 17:09:42 +0900561 sBuilder.matchIPDst(IpPrefix.valueOf(vmIp, VM_IP_PREFIX));
sangho6a9ff0d2017-03-27 11:23:37 +0900562 }
563 }
564
565 private void buildMatchEthType(TrafficSelector.Builder sBuilder, String etherType) {
566 // Either IpSrc or IpDst (or both) is set by default, and we need to set EthType as IPv4.
567 sBuilder.matchEthType(Ethernet.TYPE_IPV4);
568 if (etherType != null && !Objects.equals(etherType, "null") &&
569 !etherType.toUpperCase().equals(ETHTYPE_IPV4)) {
570 log.debug("EthType {} is not supported yet in Security Group", etherType);
571 }
572 }
573
Jian Libcc42282018-09-13 20:59:34 +0900574 private void buildMatchRemoteIp(TrafficSelector.Builder sBuilder,
575 IpPrefix remoteIpPrefix, String direction) {
576 if (remoteIpPrefix != null &&
577 !remoteIpPrefix.getIp4Prefix().equals(IP_PREFIX_ANY)) {
sangho6a9ff0d2017-03-27 11:23:37 +0900578 if (direction.toUpperCase().equals(EGRESS)) {
579 sBuilder.matchIPDst(remoteIpPrefix);
580 } else {
581 sBuilder.matchIPSrc(remoteIpPrefix);
582 }
583 }
584 }
585
586 private void buildMatchProto(TrafficSelector.Builder sBuilder, String protocol) {
587 if (protocol != null) {
588 switch (protocol.toUpperCase()) {
589 case PROTO_ICMP:
590 sBuilder.matchIPProtocol(IPv4.PROTOCOL_ICMP);
591 break;
592 case PROTO_TCP:
593 sBuilder.matchIPProtocol(IPv4.PROTOCOL_TCP);
594 break;
595 case PROTO_UDP:
596 sBuilder.matchIPProtocol(IPv4.PROTOCOL_UDP);
597 break;
598 default:
599 }
600 }
601 }
602
Jian Libcc42282018-09-13 20:59:34 +0900603 private void buildMatchPort(TrafficSelector.Builder sBuilder,
604 String protocol, String direction,
sangho6a9ff0d2017-03-27 11:23:37 +0900605 int portMin, int portMax) {
606 if (portMin > 0 && portMax > 0 && portMin == portMax) {
607 if (protocol.toUpperCase().equals(PROTO_TCP)) {
608 if (direction.toUpperCase().equals(EGRESS)) {
609 sBuilder.matchTcpSrc(TpPort.tpPort(portMax));
610 } else {
611 sBuilder.matchTcpDst(TpPort.tpPort(portMax));
612 }
613 } else if (protocol.toUpperCase().equals(PROTO_UDP)) {
614 if (direction.toUpperCase().equals(EGRESS)) {
615 sBuilder.matchUdpSrc(TpPort.tpPort(portMax));
616 } else {
617 sBuilder.matchUdpDst(TpPort.tpPort(portMax));
618 }
619 }
620 }
621 }
622
sangho0248ca22017-05-31 13:22:47 +0900623 private void resetSecurityGroupRules() {
624
625 if (useSecurityGroup) {
Jian Lib6969502018-10-30 20:38:07 +0900626 osNodeService.completeNodes(COMPUTE).forEach(node -> {
627 osFlowRuleService.setUpTableMissEntry(node.intgBridge(), ACL_TABLE);
628 initializeConnTrackTable(node.intgBridge(), true);
629 });
630
sangho0248ca22017-05-31 13:22:47 +0900631 securityGroupService.securityGroups().forEach(securityGroup ->
632 securityGroup.getRules().forEach(this::securityGroupRuleAdded));
633 } else {
Jian Lib6969502018-10-30 20:38:07 +0900634 osNodeService.completeNodes(COMPUTE).forEach(node -> {
635 osFlowRuleService.connectTables(node.intgBridge(), ACL_TABLE, JUMP_TABLE);
636 initializeConnTrackTable(node.intgBridge(), false);
637 });
638
sangho0248ca22017-05-31 13:22:47 +0900639 securityGroupService.securityGroups().forEach(securityGroup ->
640 securityGroup.getRules().forEach(this::securityGroupRuleRemoved));
641 }
642
Jian Libcc42282018-09-13 20:59:34 +0900643 log.info("Reset security group info " +
Jian Li28ec77f2018-10-31 07:07:25 +0900644 (useSecurityGroup ? " with " : " without") + " Security Group");
sangho0248ca22017-05-31 13:22:47 +0900645 }
646
647 private void securityGroupRuleAdded(SecurityGroupRule sgRule) {
648 osNetService.ports().stream()
Jian Libcc42282018-09-13 20:59:34 +0900649 .filter(port -> port.getSecurityGroups()
Jian Li28ec77f2018-10-31 07:07:25 +0900650 .contains(sgRule.getSecurityGroupId()))
sangho0248ca22017-05-31 13:22:47 +0900651 .forEach(port -> {
652 updateSecurityGroupRule(
653 instancePortService.instancePort(port.getId()),
654 port, sgRule, true);
655 log.debug("Applied security group rule {} to port {}",
656 sgRule.getId(), port.getId());
657 });
658 }
659
660 private void securityGroupRuleRemoved(SecurityGroupRule sgRule) {
Jian Liac30e272018-10-18 23:08:03 +0900661 Set<Port> removedPorts = new HashSet<>(removedOsPortStore.asJavaMap().values());
662
663 Sets.union(osNetService.ports(), removedPorts).stream()
Jian Libcc42282018-09-13 20:59:34 +0900664 .filter(port -> port.getSecurityGroups()
Jian Li28ec77f2018-10-31 07:07:25 +0900665 .contains(sgRule.getSecurityGroupId()))
sangho0248ca22017-05-31 13:22:47 +0900666 .forEach(port -> {
667 updateSecurityGroupRule(
668 instancePortService.instancePort(port.getId()),
669 port, sgRule, false);
670 log.debug("Removed security group rule {} from port {}",
671 sgRule.getId(), port.getId());
672 });
673 }
674
sangho2e97be02017-07-03 18:18:27 +0900675 private int binLower(String binStr, int bits) {
Jian Li2b9838c2018-10-28 17:09:42 +0900676 StringBuilder outBin = new StringBuilder(binStr.substring(0, 16 - bits));
sangho2e97be02017-07-03 18:18:27 +0900677 for (int i = 0; i < bits; i++) {
Jian Li2b9838c2018-10-28 17:09:42 +0900678 outBin.append("0");
sangho2e97be02017-07-03 18:18:27 +0900679 }
680
Jian Li2b9838c2018-10-28 17:09:42 +0900681 return Integer.parseInt(outBin.toString(), 2);
sangho2e97be02017-07-03 18:18:27 +0900682 }
683
684 private int binHigher(String binStr, int bits) {
Jian Li2b9838c2018-10-28 17:09:42 +0900685 StringBuilder outBin = new StringBuilder(binStr.substring(0, 16 - bits));
sangho2e97be02017-07-03 18:18:27 +0900686 for (int i = 0; i < bits; i++) {
Jian Li2b9838c2018-10-28 17:09:42 +0900687 outBin.append("1");
sangho2e97be02017-07-03 18:18:27 +0900688 }
689
Jian Li2b9838c2018-10-28 17:09:42 +0900690 return Integer.parseInt(outBin.toString(), 2);
sangho2e97be02017-07-03 18:18:27 +0900691 }
692
693 private int testMasks(String binStr, int start, int end) {
694 int mask = 0;
695 for (; mask <= 16; mask++) {
696 int maskStart = binLower(binStr, mask);
697 int maskEnd = binHigher(binStr, mask);
698 if (maskStart < start || maskEnd > end) {
699 return mask - 1;
700 }
701 }
702
703 return mask;
704 }
705
706 private String getMask(int bits) {
707 switch (bits) {
708 case 0: return "ffff";
709 case 1: return "fffe";
710 case 2: return "fffc";
711 case 3: return "fff8";
712 case 4: return "fff0";
713 case 5: return "ffe0";
714 case 6: return "ffc0";
715 case 7: return "ff80";
716 case 8: return "ff00";
717 case 9: return "fe00";
718 case 10: return "fc00";
719 case 11: return "f800";
720 case 12: return "f000";
721 case 13: return "e000";
722 case 14: return "c000";
723 case 15: return "8000";
724 case 16: return "0000";
725 default: return null;
726 }
727 }
728
729 private Map<TpPort, TpPort> buildPortRangeMatches(int portMin, int portMax) {
730
731 boolean processing = true;
732 int start = portMin;
733 Map<TpPort, TpPort> portMaskMap = Maps.newHashMap();
734 while (processing) {
735 String minStr = Integer.toBinaryString(start);
736 String binStrMinPadded = "0000000000000000".substring(minStr.length()) + minStr;
737
738 int mask = testMasks(binStrMinPadded, start, portMax);
739 int maskStart = binLower(binStrMinPadded, mask);
740 int maskEnd = binHigher(binStrMinPadded, mask);
741
742 log.debug("start : {} port/mask = {} / {} ", start, getMask(mask), maskStart);
Jian Libcc42282018-09-13 20:59:34 +0900743 portMaskMap.put(TpPort.tpPort(maskStart), TpPort.tpPort(
744 Integer.parseInt(Objects.requireNonNull(getMask(mask)), 16)));
sangho2e97be02017-07-03 18:18:27 +0900745
746 start = maskEnd + 1;
747 if (start > portMax) {
748 processing = false;
749 }
750 }
751
752 return portMaskMap;
753 }
754
sangho6a9ff0d2017-03-27 11:23:37 +0900755 private class InternalInstancePortListener implements InstancePortListener {
756
757 @Override
758 public boolean isRelevant(InstancePortEvent event) {
Jian Li2b9838c2018-10-28 17:09:42 +0900759 return useSecurityGroup &&
760 mastershipService.isLocalMaster(event.subject().deviceId());
sangho6a9ff0d2017-03-27 11:23:37 +0900761 }
762
763 @Override
764 public void event(InstancePortEvent event) {
765 InstancePort instPort = event.subject();
766 switch (event.type()) {
Jian Liec5c32b2018-07-13 14:28:58 +0900767 case OPENSTACK_INSTANCE_PORT_UPDATED:
Jian Lie8b28db2018-10-17 14:04:09 +0900768 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Liac30e272018-10-18 23:08:03 +0900769 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
770 installSecurityGroupRules(event, instPort);
771 break;
772 case OPENSTACK_INSTANCE_PORT_VANISHED:
773 Port osPort = removedOsPortStore.asJavaMap().get(instPort.portId());
774 eventExecutor.execute(() ->
775 setSecurityGroupRules(instPort, osPort, false)
776 );
777 removedOsPortStore.remove(instPort.portId());
sangho6a9ff0d2017-03-27 11:23:37 +0900778 break;
Jian Lib8cdcc12018-10-23 01:53:10 +0900779 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
780 InstancePort revisedInstPort = swapStaleLocation(instPort);
781 Port port = osNetService.port(instPort.portId());
782 eventExecutor.execute(() ->
783 setSecurityGroupRules(revisedInstPort, port, false));
784 break;
sangho6a9ff0d2017-03-27 11:23:37 +0900785 default:
786 break;
787 }
788 }
Jian Liac30e272018-10-18 23:08:03 +0900789
790 private void installSecurityGroupRules(InstancePortEvent event,
791 InstancePort instPort) {
792 log.debug("Instance port detected/updated MAC:{} IP:{}",
793 instPort.macAddress(),
794 instPort.ipAddress());
Jian Li2b9838c2018-10-28 17:09:42 +0900795 eventExecutor.execute(() ->
796 setSecurityGroupRules(instPort,
797 osNetService.port(event.subject().portId()), true));
Jian Liac30e272018-10-18 23:08:03 +0900798 }
sangho6a9ff0d2017-03-27 11:23:37 +0900799 }
800
801 private class InternalOpenstackPortListener implements OpenstackNetworkListener {
802
803 @Override
804 public boolean isRelevant(OpenstackNetworkEvent event) {
sanghoshinbbeb31a2018-09-11 17:01:01 +0800805 if (event.port() == null || Strings.isNullOrEmpty(event.port().getId())) {
sangho6a9ff0d2017-03-27 11:23:37 +0900806 return false;
807 }
Jian Libcc42282018-09-13 20:59:34 +0900808
809 InstancePort instPort = instancePortService.instancePort(event.port().getId());
810
811 if (instPort == null) {
812 return false;
813 }
814
815 return useSecurityGroup && mastershipService.isLocalMaster(instPort.deviceId());
816 }
817
818 @Override
819 public void event(OpenstackNetworkEvent event) {
820 log.debug("openstack port event received {}", event);
821 Port osPort = event.port();
Jian Libcc42282018-09-13 20:59:34 +0900822
823 switch (event.type()) {
824 case OPENSTACK_PORT_PRE_REMOVE:
Jian Liac30e272018-10-18 23:08:03 +0900825 removedOsPortStore.put(osPort.getId(), osPort);
Jian Libcc42282018-09-13 20:59:34 +0900826 break;
827 default:
828 // do nothing for the other events
829 break;
830 }
831 }
832 }
833
Jian Li2b9838c2018-10-28 17:09:42 +0900834 private class InternalOpenstackNetworkListener
Jian Li28ec77f2018-10-31 07:07:25 +0900835 implements OpenstackNetworkListener {
Jian Libcc42282018-09-13 20:59:34 +0900836
837 @Override
838 public boolean isRelevant(OpenstackNetworkEvent event) {
839 if (event.port() == null || Strings.isNullOrEmpty(event.port().getId())) {
840 return false;
841 }
Jian Li2b9838c2018-10-28 17:09:42 +0900842
Hyunsun Moonae51e732017-04-25 17:46:21 +0900843 if (event.securityGroupId() == null ||
844 securityGroupService.securityGroup(event.securityGroupId()) == null) {
845 return false;
846 }
Jian Li2b9838c2018-10-28 17:09:42 +0900847
848 InstancePort instPort = instancePortService.instancePort(event.port().getId());
849
850 if (instPort == null) {
Hyunsun Moonae51e732017-04-25 17:46:21 +0900851 return false;
852 }
Jian Li2b9838c2018-10-28 17:09:42 +0900853
854 return useSecurityGroup && mastershipService.isLocalMaster(instPort.deviceId());
sangho6a9ff0d2017-03-27 11:23:37 +0900855 }
856
857 @Override
858 public void event(OpenstackNetworkEvent event) {
sanghoshinbbeb31a2018-09-11 17:01:01 +0800859 log.debug("security group event received {}", event);
Hyunsun Moonae51e732017-04-25 17:46:21 +0900860 Port osPort = event.port();
861 InstancePort instPort = instancePortService.instancePort(osPort.getId());
862 SecurityGroup osSg = securityGroupService.securityGroup(event.securityGroupId());
863
sangho6a9ff0d2017-03-27 11:23:37 +0900864 switch (event.type()) {
Hyunsun Moonae51e732017-04-25 17:46:21 +0900865 case OPENSTACK_PORT_SECURITY_GROUP_ADDED:
866 eventExecutor.execute(() -> {
867 osSg.getRules().forEach(sgRule -> {
868 updateSecurityGroupRule(instPort, osPort, sgRule, true);
869 });
870 log.info("Added security group {} to port {}",
871 event.securityGroupId(), event.port().getId());
872 });
sangho6a9ff0d2017-03-27 11:23:37 +0900873 break;
Hyunsun Moonae51e732017-04-25 17:46:21 +0900874 case OPENSTACK_PORT_SECURITY_GROUP_REMOVED:
875 eventExecutor.execute(() -> {
876 osSg.getRules().forEach(sgRule -> {
877 updateSecurityGroupRule(instPort, osPort, sgRule, false);
878 });
879 log.info("Removed security group {} from port {}",
880 event.securityGroupId(), event.port().getId());
881 });
sangho6a9ff0d2017-03-27 11:23:37 +0900882 break;
883 default:
Hyunsun Moonae51e732017-04-25 17:46:21 +0900884 // do nothing for the other events
sangho6a9ff0d2017-03-27 11:23:37 +0900885 break;
886 }
887 }
sangho6a9ff0d2017-03-27 11:23:37 +0900888 }
889
Jian Li2b9838c2018-10-28 17:09:42 +0900890 private class InternalSecurityGroupListener
Jian Li28ec77f2018-10-31 07:07:25 +0900891 implements OpenstackSecurityGroupListener {
sangho6a9ff0d2017-03-27 11:23:37 +0900892
893 @Override
sangho0248ca22017-05-31 13:22:47 +0900894 public boolean isRelevant(OpenstackSecurityGroupEvent event) {
Jian Liac30e272018-10-18 23:08:03 +0900895 // do not allow to proceed without leadership
896 NodeId leader = leadershipService.getLeader(appId.name());
897 if (!Objects.equals(localNodeId, leader)) {
898 return false;
899 }
Jian Libcc42282018-09-13 20:59:34 +0900900 return useSecurityGroup;
sangho0248ca22017-05-31 13:22:47 +0900901 }
902
903 @Override
sangho6a9ff0d2017-03-27 11:23:37 +0900904 public void event(OpenstackSecurityGroupEvent event) {
905 switch (event.type()) {
sangho6a9ff0d2017-03-27 11:23:37 +0900906 case OPENSTACK_SECURITY_GROUP_RULE_CREATED:
Jian Li2b9838c2018-10-28 17:09:42 +0900907 SecurityGroupRule sgRuleToAdd = event.securityGroupRule();
sangho6a9ff0d2017-03-27 11:23:37 +0900908 eventExecutor.execute(() -> {
Jian Li2b9838c2018-10-28 17:09:42 +0900909 securityGroupRuleAdded(sgRuleToAdd);
Hyunsun Moonae51e732017-04-25 17:46:21 +0900910 log.info("Applied new security group rule {} to ports",
Jian Li2b9838c2018-10-28 17:09:42 +0900911 sgRuleToAdd.getId());
sangho6a9ff0d2017-03-27 11:23:37 +0900912 });
913 break;
914
915 case OPENSTACK_SECURITY_GROUP_RULE_REMOVED:
Jian Li2b9838c2018-10-28 17:09:42 +0900916 SecurityGroupRule sgRuleToRemove = event.securityGroupRule();
sangho6a9ff0d2017-03-27 11:23:37 +0900917 eventExecutor.execute(() -> {
Jian Li2b9838c2018-10-28 17:09:42 +0900918 securityGroupRuleRemoved(sgRuleToRemove);
Hyunsun Moonae51e732017-04-25 17:46:21 +0900919 log.info("Removed security group rule {} from ports",
Jian Li2b9838c2018-10-28 17:09:42 +0900920 sgRuleToRemove.getId());
sangho6a9ff0d2017-03-27 11:23:37 +0900921 });
922 break;
Hyunsun Moonae51e732017-04-25 17:46:21 +0900923 case OPENSTACK_SECURITY_GROUP_REMOVED:
Jian Li9d35bd62018-10-13 01:43:24 +0900924 case OPENSTACK_SECURITY_GROUP_CREATED:
sangho6a9ff0d2017-03-27 11:23:37 +0900925 default:
Hyunsun Moonae51e732017-04-25 17:46:21 +0900926 // do nothing
927 break;
sangho6a9ff0d2017-03-27 11:23:37 +0900928 }
929 }
sangho6a9ff0d2017-03-27 11:23:37 +0900930 }
sangho1aaa7882017-05-31 13:22:47 +0900931
932 private class InternalNodeListener implements OpenstackNodeListener {
933
934 @Override
935 public boolean isRelevant(OpenstackNodeEvent event) {
936 // do not allow to proceed without leadership
937 NodeId leader = leadershipService.getLeader(appId.name());
938 if (!Objects.equals(localNodeId, leader)) {
939 return false;
940 }
941 return event.subject().type() == COMPUTE;
942 }
943
944 @Override
945 public void event(OpenstackNodeEvent event) {
sangho1aaa7882017-05-31 13:22:47 +0900946 switch (event.type()) {
947 case OPENSTACK_NODE_COMPLETE:
Jian Lib6969502018-10-30 20:38:07 +0900948 resetSecurityGroupRules();
sangho1aaa7882017-05-31 13:22:47 +0900949 break;
950 case OPENSTACK_NODE_CREATED:
951 case OPENSTACK_NODE_REMOVED:
952 case OPENSTACK_NODE_UPDATED:
953 case OPENSTACK_NODE_INCOMPLETE:
954 default:
955 break;
956 }
957 }
958 }
Jian Libcc42282018-09-13 20:59:34 +0900959}