blob: c36617804157877f531ceb8e9035ef962fb05d47 [file] [log] [blame]
Hyunsun Moon44aac662017-02-18 02:07:01 +09001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Hyunsun Moon44aac662017-02-18 02:07:01 +09003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.openstacknetworking.impl;
17
18import com.google.common.base.Strings;
19import com.google.common.collect.ImmutableSet;
Daniel Park613ac372018-06-28 14:30:11 +090020import com.google.common.collect.Sets;
Hyunsun Moon44aac662017-02-18 02:07:01 +090021import org.onlab.packet.Ethernet;
22import org.onlab.packet.IPv4;
23import org.onlab.packet.IpAddress;
24import org.onlab.packet.IpPrefix;
sangho072c4dd2017-05-17 10:45:21 +090025import org.onlab.packet.MacAddress;
daniel parkee8700b2017-05-11 15:50:03 +090026import org.onlab.packet.VlanId;
sanghoe765ce22017-06-23 17:54:57 +090027import org.onlab.util.Tools;
28import org.onosproject.cfg.ComponentConfigService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090029import org.onosproject.cluster.ClusterService;
30import org.onosproject.cluster.LeadershipService;
31import org.onosproject.cluster.NodeId;
32import org.onosproject.core.ApplicationId;
33import org.onosproject.core.CoreService;
sangho072c4dd2017-05-17 10:45:21 +090034import org.onosproject.mastership.MastershipService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090035import org.onosproject.net.DeviceId;
36import org.onosproject.net.PortNumber;
sangho072c4dd2017-05-17 10:45:21 +090037import org.onosproject.net.device.DeviceService;
38import org.onosproject.net.driver.DriverService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090039import org.onosproject.net.flow.DefaultTrafficSelector;
40import org.onosproject.net.flow.DefaultTrafficTreatment;
41import org.onosproject.net.flow.TrafficSelector;
42import org.onosproject.net.flow.TrafficTreatment;
sangho072c4dd2017-05-17 10:45:21 +090043import org.onosproject.net.flow.instructions.ExtensionTreatment;
Hyunsun Moon44aac662017-02-18 02:07:01 +090044import org.onosproject.openstacknetworking.api.Constants;
daniel park576969a2018-03-09 07:07:41 +090045import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
sangho072c4dd2017-05-17 10:45:21 +090046import org.onosproject.openstacknetworking.api.InstancePort;
47import org.onosproject.openstacknetworking.api.InstancePortEvent;
48import org.onosproject.openstacknetworking.api.InstancePortListener;
49import org.onosproject.openstacknetworking.api.InstancePortService;
sanghodc375372017-06-08 10:41:30 +090050import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
daniel park32b42202018-03-14 16:53:44 +090051import org.onosproject.openstacknetworking.api.OpenstackNetworkAdminService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090052import org.onosproject.openstacknetworking.api.OpenstackRouterEvent;
53import org.onosproject.openstacknetworking.api.OpenstackRouterListener;
54import org.onosproject.openstacknetworking.api.OpenstackRouterService;
Jian Li26949762018-03-30 15:46:37 +090055import org.onosproject.openstacknetworking.util.RulePopulatorUtil;
Hyunsun Moon0d457362017-06-27 17:19:41 +090056import org.onosproject.openstacknode.api.OpenstackNode;
57import org.onosproject.openstacknode.api.OpenstackNode.NetworkMode;
58import org.onosproject.openstacknode.api.OpenstackNodeEvent;
59import org.onosproject.openstacknode.api.OpenstackNodeListener;
60import org.onosproject.openstacknode.api.OpenstackNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090061import org.openstack4j.model.network.ExternalGateway;
62import org.openstack4j.model.network.Network;
daniel parkee8700b2017-05-11 15:50:03 +090063import org.openstack4j.model.network.NetworkType;
Hyunsun Moon44aac662017-02-18 02:07:01 +090064import org.openstack4j.model.network.Router;
65import org.openstack4j.model.network.RouterInterface;
66import org.openstack4j.model.network.Subnet;
sanghoe765ce22017-06-23 17:54:57 +090067import org.osgi.service.component.ComponentContext;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070068import org.osgi.service.component.annotations.Activate;
69import org.osgi.service.component.annotations.Component;
70import org.osgi.service.component.annotations.Deactivate;
71import org.osgi.service.component.annotations.Modified;
72import org.osgi.service.component.annotations.Reference;
73import org.osgi.service.component.annotations.ReferenceCardinality;
Hyunsun Moon44aac662017-02-18 02:07:01 +090074import org.slf4j.Logger;
75import org.slf4j.LoggerFactory;
76
sanghoe765ce22017-06-23 17:54:57 +090077import java.util.Dictionary;
Hyunsun Moon44aac662017-02-18 02:07:01 +090078import java.util.Objects;
sangho072c4dd2017-05-17 10:45:21 +090079import java.util.Optional;
Hyunsun Moon44aac662017-02-18 02:07:01 +090080import java.util.Set;
81import java.util.concurrent.ExecutorService;
82import java.util.stream.Collectors;
83
84import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
85import static org.onlab.util.Tools.groupedThreads;
sangho072c4dd2017-05-17 10:45:21 +090086import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_EXTERNAL_ROUTER_MAC;
87import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_GATEWAY_MAC;
sangho072c4dd2017-05-17 10:45:21 +090088import static org.onosproject.openstacknetworking.api.Constants.GW_COMMON_TABLE;
89import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
daniel park796c2eb2018-03-22 17:01:51 +090090import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ADMIN_RULE;
sangho072c4dd2017-05-17 10:45:21 +090091import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_EXTERNAL_ROUTING_RULE;
92import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ICMP_RULE;
93import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_INTERNAL_ROUTING_RULE;
sanghoe765ce22017-06-23 17:54:57 +090094import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_STATEFUL_SNAT_RULE;
sangho072c4dd2017-05-17 10:45:21 +090095import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_SWITCHING_RULE;
96import static org.onosproject.openstacknetworking.api.Constants.ROUTING_TABLE;
Jian Li8abf2fe2018-06-12 18:42:30 +090097import static org.onosproject.openstacknetworking.api.Constants.STAT_OUTBOUND_TABLE;
Jian Lic2403592018-07-18 12:56:45 +090098import static org.onosproject.openstacknetworking.api.InstancePort.State.ACTIVE;
Ray Milkey8e406512018-10-24 15:56:50 -070099import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.USE_STATEFUL_SNAT;
100import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.USE_STATEFUL_SNAT_DEFAULT;
Jian Li26949762018-03-30 15:46:37 +0900101import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900102import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
103import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Jian Li32b03622018-11-06 17:54:24 +0900104import static org.openstack4j.model.network.NetworkType.FLAT;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900105
106/**
107 * Handles OpenStack router events.
108 */
Ray Milkey8e406512018-10-24 15:56:50 -0700109@Component(
110 immediate = true,
111 property = {
112 USE_STATEFUL_SNAT + ":Boolean=" + USE_STATEFUL_SNAT_DEFAULT
113 }
114)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900115public class OpenstackRoutingHandler {
116
117 private final Logger log = LoggerFactory.getLogger(getClass());
118
119 private static final String MSG_ENABLED = "Enabled ";
120 private static final String MSG_DISABLED = "Disabled ";
daniel parkee8700b2017-05-11 15:50:03 +0900121 private static final String ERR_UNSUPPORTED_NET_TYPE = "Unsupported network type";
sanghoe765ce22017-06-23 17:54:57 +0900122
Jian Li4d138702018-11-27 17:25:28 +0900123 private static final int VM_PREFIX = 32;
124
Ray Milkey8e406512018-10-24 15:56:50 -0700125 /** Use Stateful SNAT for source NATing. */
126 private boolean useStatefulSnat = USE_STATEFUL_SNAT_DEFAULT;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900127
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700128 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900129 protected CoreService coreService;
130
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700131 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900132 protected LeadershipService leadershipService;
133
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700134 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900135 protected ClusterService clusterService;
136
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700137 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900138 protected OpenstackNodeService osNodeService;
139
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700140 @Reference(cardinality = ReferenceCardinality.MANDATORY)
daniel park32b42202018-03-14 16:53:44 +0900141 protected OpenstackNetworkAdminService osNetworkAdminService;
142
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700143 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900144 protected OpenstackRouterService osRouterService;
145
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700146 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho072c4dd2017-05-17 10:45:21 +0900147 protected InstancePortService instancePortService;
148
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700149 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho072c4dd2017-05-17 10:45:21 +0900150 protected DeviceService deviceService;
151
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700152 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sanghodc375372017-06-08 10:41:30 +0900153 protected OpenstackFlowRuleService osFlowRuleService;
154
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700155 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho072c4dd2017-05-17 10:45:21 +0900156 protected MastershipService mastershipService;
157
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700158 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho072c4dd2017-05-17 10:45:21 +0900159 protected DriverService driverService;
160
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700161 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sanghoe765ce22017-06-23 17:54:57 +0900162 protected ComponentConfigService configService;
163
Hyunsun Moon44aac662017-02-18 02:07:01 +0900164 private final ExecutorService eventExecutor = newSingleThreadScheduledExecutor(
165 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
166 private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
167 private final OpenstackRouterListener osRouterListener = new InternalRouterEventListener();
sangho072c4dd2017-05-17 10:45:21 +0900168 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900169
170 private ApplicationId appId;
171 private NodeId localNodeId;
172
173 @Activate
174 protected void activate() {
175 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
176 localNodeId = clusterService.getLocalNode().id();
177 leadershipService.runForLeadership(appId.name());
178 osNodeService.addListener(osNodeListener);
179 osRouterService.addListener(osRouterListener);
sangho072c4dd2017-05-17 10:45:21 +0900180 instancePortService.addListener(instancePortListener);
sanghoe765ce22017-06-23 17:54:57 +0900181 configService.registerProperties(getClass());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900182
183 log.info("Started");
184 }
185
186 @Deactivate
187 protected void deactivate() {
188 osRouterService.removeListener(osRouterListener);
189 osNodeService.removeListener(osNodeListener);
sangho072c4dd2017-05-17 10:45:21 +0900190 instancePortService.removeListener(instancePortListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900191 leadershipService.withdraw(appId.name());
sanghoe765ce22017-06-23 17:54:57 +0900192 configService.unregisterProperties(getClass(), false);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900193 eventExecutor.shutdown();
194
195 log.info("Stopped");
196 }
197
sanghoe765ce22017-06-23 17:54:57 +0900198 @Modified
199 protected void modified(ComponentContext context) {
200 Dictionary<?, ?> properties = context.getProperties();
201 Boolean flag;
202
Ray Milkey8e406512018-10-24 15:56:50 -0700203 flag = Tools.isPropertyEnabled(properties, USE_STATEFUL_SNAT);
sanghoe765ce22017-06-23 17:54:57 +0900204 if (flag == null) {
205 log.info("useStatefulSnat is not configured, " +
206 "using current value of {}", useStatefulSnat);
207 } else {
208 useStatefulSnat = flag;
209 log.info("Configured. useStatefulSnat is {}",
210 useStatefulSnat ? "enabled" : "disabled");
211 }
212
213 resetSnatRules();
214 }
215
Hyunsun Moon44aac662017-02-18 02:07:01 +0900216 private void routerUpdated(Router osRouter) {
217 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
Frank Wang245a6822017-06-14 09:51:35 +0800218 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
Jian Liedc8b762018-03-22 15:42:00 +0900219 Network network = osNetworkAdminService.network(osNetworkAdminService.subnet(iface.getSubnetId())
Frank Wang245a6822017-06-14 09:51:35 +0800220 .getNetworkId());
221 setRouterAdminRules(network.getProviderSegID(), network.getNetworkType(), !osRouter.isAdminStateUp());
222 });
223
Jian Liedc8b762018-03-22 15:42:00 +0900224 ExternalPeerRouter externalPeerRouter = osNetworkAdminService.externalPeerRouter(exGateway);
Jian Li5e2ad4a2018-07-16 13:40:53 +0900225 VlanId vlanId = externalPeerRouter == null ? VlanId.NONE : externalPeerRouter.vlanId();
daniel park576969a2018-03-09 07:07:41 +0900226
Hyunsun Moon44aac662017-02-18 02:07:01 +0900227 if (exGateway == null) {
Daniel Park613ac372018-06-28 14:30:11 +0900228 deleteUnassociatedExternalPeerRouter();
daniel park576969a2018-03-09 07:07:41 +0900229 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> setSourceNat(iface, false));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900230 } else {
daniel park32b42202018-03-14 16:53:44 +0900231 osNetworkAdminService.deriveExternalPeerRouterMac(exGateway, osRouter, vlanId);
daniel park576969a2018-03-09 07:07:41 +0900232 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface ->
233 setSourceNat(iface, exGateway.isEnableSnat()));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900234 }
235 }
236
Daniel Park613ac372018-06-28 14:30:11 +0900237 private void deleteUnassociatedExternalPeerRouter() {
238 log.trace("Deleting unassociated external peer router");
239
240 try {
241 Set<String> routerIps = Sets.newConcurrentHashSet();
242
243 osRouterService.routers().stream()
244 .filter(router -> getGatewayIpAddress(router) != null)
245 .map(router -> getGatewayIpAddress(router).toString())
246 .forEach(routerIps::add);
247
248 osNetworkAdminService.externalPeerRouters().stream()
249 .filter(externalPeerRouter ->
Jian Li5e2ad4a2018-07-16 13:40:53 +0900250 !routerIps.contains(externalPeerRouter.ipAddress().toString()))
Daniel Park613ac372018-06-28 14:30:11 +0900251 .forEach(externalPeerRouter -> {
252 osNetworkAdminService
Jian Li5e2ad4a2018-07-16 13:40:53 +0900253 .deleteExternalPeerRouter(externalPeerRouter.ipAddress().toString());
Daniel Park613ac372018-06-28 14:30:11 +0900254 log.trace("Deleted unassociated external peer router {}",
Jian Li5e2ad4a2018-07-16 13:40:53 +0900255 externalPeerRouter.ipAddress().toString());
Daniel Park613ac372018-06-28 14:30:11 +0900256 });
257 } catch (Exception e) {
258 log.error("Exception occurred because of {}", e.toString());
259 }
260 }
261
Frank Wang245a6822017-06-14 09:51:35 +0800262 private void routerRemove(Router osRouter) {
263 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
Jian Liedc8b762018-03-22 15:42:00 +0900264 Network network = osNetworkAdminService.network(osNetworkAdminService.subnet(iface.getSubnetId())
Frank Wang245a6822017-06-14 09:51:35 +0800265 .getNetworkId());
266 setRouterAdminRules(network.getProviderSegID(), network.getNetworkType(), false);
267 });
268 }
269
Hyunsun Moon44aac662017-02-18 02:07:01 +0900270 private void routerIfaceAdded(Router osRouter, RouterInterface osRouterIface) {
Jian Liedc8b762018-03-22 15:42:00 +0900271 Subnet osSubnet = osNetworkAdminService.subnet(osRouterIface.getSubnetId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900272 if (osSubnet == null) {
273 final String error = String.format(
Jian Li71670d12018-03-02 21:31:07 +0900274 "Failed to set flows for router %s: subnet %s does not exist",
Hyunsun Moon44aac662017-02-18 02:07:01 +0900275 osRouterIface.getId(),
276 osRouterIface.getSubnetId());
277 throw new IllegalStateException(error);
278 }
Frank Wang245a6822017-06-14 09:51:35 +0800279
280 if (!osRouter.isAdminStateUp()) {
Jian Liedc8b762018-03-22 15:42:00 +0900281 Network network = osNetworkAdminService.network(osSubnet.getNetworkId());
Frank Wang245a6822017-06-14 09:51:35 +0800282 setRouterAdminRules(network.getProviderSegID(), network.getNetworkType(), true);
283 }
284
Hyunsun Moon44aac662017-02-18 02:07:01 +0900285 setInternalRoutes(osRouter, osSubnet, true);
Daniel Park51f9d1e2018-10-26 13:39:09 +0900286 setGatewayIcmp(osSubnet, osRouter, true);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900287 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
288 if (exGateway != null && exGateway.isEnableSnat()) {
daniel park576969a2018-03-09 07:07:41 +0900289 setSourceNat(osRouterIface, true);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900290 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900291 log.info("Connected subnet({}) to {}", osSubnet.getCidr(), osRouter.getName());
292 }
293
294 private void routerIfaceRemoved(Router osRouter, RouterInterface osRouterIface) {
Jian Liedc8b762018-03-22 15:42:00 +0900295 Subnet osSubnet = osNetworkAdminService.subnet(osRouterIface.getSubnetId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900296 if (osSubnet == null) {
297 final String error = String.format(
Jian Li71670d12018-03-02 21:31:07 +0900298 "Failed to set flows for router %s: subnet %s does not exist",
Hyunsun Moon44aac662017-02-18 02:07:01 +0900299 osRouterIface.getId(),
300 osRouterIface.getSubnetId());
301 throw new IllegalStateException(error);
302 }
303
Frank Wang245a6822017-06-14 09:51:35 +0800304 if (!osRouter.isAdminStateUp()) {
Jian Liedc8b762018-03-22 15:42:00 +0900305 Network network = osNetworkAdminService.network(osSubnet.getNetworkId());
Frank Wang245a6822017-06-14 09:51:35 +0800306 setRouterAdminRules(network.getProviderSegID(), network.getNetworkType(), false);
307 }
308
Hyunsun Moon44aac662017-02-18 02:07:01 +0900309 setInternalRoutes(osRouter, osSubnet, false);
Daniel Park51f9d1e2018-10-26 13:39:09 +0900310 setGatewayIcmp(osSubnet, osRouter, false);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900311 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
312 if (exGateway != null && exGateway.isEnableSnat()) {
daniel park576969a2018-03-09 07:07:41 +0900313 setSourceNat(osRouterIface, false);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900314 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900315 log.info("Disconnected subnet({}) from {}", osSubnet.getCidr(), osRouter.getName());
316 }
317
daniel park576969a2018-03-09 07:07:41 +0900318 private void setSourceNat(RouterInterface routerIface, boolean install) {
Jian Liedc8b762018-03-22 15:42:00 +0900319 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
320 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900321
Hyunsun Moon0d457362017-06-27 17:19:41 +0900322 osNodeService.completeNodes(COMPUTE).forEach(cNode -> {
323 setRulesToGateway(cNode, osNet.getProviderSegID(),
324 IpPrefix.valueOf(osSubnet.getCidr()), osNet.getNetworkType(),
325 install);
326 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900327
sanghoe765ce22017-06-23 17:54:57 +0900328 if (useStatefulSnat) {
329 setStatefulSnatRules(routerIface, install);
330 } else {
331 setReactiveSnatRules(routerIface, install);
332 }
333
334 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
335 log.info(updateStr + "external access for subnet({})", osSubnet.getCidr());
336 }
337
338 private void setStatefulSnatRules(RouterInterface routerIface, boolean install) {
Jian Liedc8b762018-03-22 15:42:00 +0900339 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
340 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
sanghoe765ce22017-06-23 17:54:57 +0900341
Jian Li32b03622018-11-06 17:54:24 +0900342 if (osNet.getNetworkType() == FLAT) {
daniel park796c2eb2018-03-22 17:01:51 +0900343 return;
344 }
345
sanghoe765ce22017-06-23 17:54:57 +0900346 Optional<Router> osRouter = osRouterService.routers().stream()
347 .filter(router -> osRouterService.routerInterfaces(routerIface.getId()) != null)
348 .findAny();
349
350 if (!osRouter.isPresent()) {
351 log.error("Cannot find a router for router interface {} ", routerIface);
352 return;
353 }
354 IpAddress natAddress = getGatewayIpAddress(osRouter.get());
sangho072c4dd2017-05-17 10:45:21 +0900355 if (natAddress == null) {
356 return;
357 }
Jian Liedc8b762018-03-22 15:42:00 +0900358 String netId = osNetworkAdminService.subnet(routerIface.getSubnetId()).getNetworkId();
sangho072c4dd2017-05-17 10:45:21 +0900359
360 osNodeService.completeNodes(OpenstackNode.NodeType.GATEWAY)
361 .forEach(gwNode -> {
daniel park576969a2018-03-09 07:07:41 +0900362 instancePortService.instancePorts(netId)
Jian Lic2403592018-07-18 12:56:45 +0900363 .stream()
364 .filter(port -> port.state() == ACTIVE)
daniel park576969a2018-03-09 07:07:41 +0900365 .forEach(port -> setRulesForSnatIngressRule(gwNode.intgBridge(),
sangho072c4dd2017-05-17 10:45:21 +0900366 Long.parseLong(osNet.getProviderSegID()),
Jian Li4d138702018-11-27 17:25:28 +0900367 IpPrefix.valueOf(port.ipAddress(), VM_PREFIX),
sangho072c4dd2017-05-17 10:45:21 +0900368 port.deviceId(),
369 install));
370
371 setOvsNatIngressRule(gwNode.intgBridge(),
Jian Li4d138702018-11-27 17:25:28 +0900372 IpPrefix.valueOf(natAddress, VM_PREFIX),
sangho072c4dd2017-05-17 10:45:21 +0900373 Constants.DEFAULT_EXTERNAL_ROUTER_MAC, install);
374 setOvsNatEgressRule(gwNode.intgBridge(),
375 natAddress, Long.parseLong(osNet.getProviderSegID()),
376 gwNode.patchPortNum(), install);
377 });
sanghoe765ce22017-06-23 17:54:57 +0900378 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900379
sanghoe765ce22017-06-23 17:54:57 +0900380 private void setReactiveSnatRules(RouterInterface routerIface, boolean install) {
Jian Liedc8b762018-03-22 15:42:00 +0900381 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
382 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
sanghoe765ce22017-06-23 17:54:57 +0900383
384 osNodeService.completeNodes(GATEWAY)
385 .forEach(gwNode -> setRulesToController(
386 gwNode.intgBridge(),
387 osNet.getProviderSegID(),
388 IpPrefix.valueOf(osSubnet.getCidr()),
389 osNet.getNetworkType(),
390 install));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900391 }
392
sangho072c4dd2017-05-17 10:45:21 +0900393 private IpAddress getGatewayIpAddress(Router osRouter) {
394
Daniel Park613ac372018-06-28 14:30:11 +0900395 if (osRouter.getExternalGatewayInfo() == null) {
396 return null;
397 }
Jian Liedc8b762018-03-22 15:42:00 +0900398 String extNetId = osNetworkAdminService.network(osRouter.getExternalGatewayInfo().getNetworkId()).getId();
399 Optional<Subnet> extSubnet = osNetworkAdminService.subnets().stream()
sangho072c4dd2017-05-17 10:45:21 +0900400 .filter(subnet -> subnet.getNetworkId().equals(extNetId))
401 .findAny();
402
403 if (!extSubnet.isPresent()) {
404 log.error("Cannot find externel subnet for the router");
405 return null;
406 }
407
408 return IpAddress.valueOf(extSubnet.get().getGateway());
409 }
410
sanghoe765ce22017-06-23 17:54:57 +0900411 private void resetSnatRules() {
412 if (useStatefulSnat) {
413 osRouterService.routerInterfaces().forEach(
414 routerIface -> {
415 setReactiveSnatRules(routerIface, false);
416 setStatefulSnatRules(routerIface, true);
417 }
418 );
419 } else {
420 osRouterService.routerInterfaces().forEach(
421 routerIface -> {
422 setStatefulSnatRules(routerIface, false);
423 setReactiveSnatRules(routerIface, true);
424 }
425 );
426 }
427 }
428
Daniel Park51f9d1e2018-10-26 13:39:09 +0900429 private void setGatewayIcmp(Subnet osSubnet, Router osRouter, boolean install) {
Jian Li4d138702018-11-27 17:25:28 +0900430 OpenstackNode srcNatGw = osNodeService.completeNodes(GATEWAY)
431 .stream().findFirst().orElse(null);
daniel parkb5817102018-02-15 00:18:51 +0900432
Jian Li4d138702018-11-27 17:25:28 +0900433 if (srcNatGw == null) {
daniel parkb5817102018-02-15 00:18:51 +0900434 return;
435 }
436
Hyunsun Moon44aac662017-02-18 02:07:01 +0900437 if (Strings.isNullOrEmpty(osSubnet.getGateway())) {
438 // do nothing if no gateway is set
439 return;
440 }
441
442 // take ICMP request to a subnet gateway through gateway node group
Jian Li4d138702018-11-27 17:25:28 +0900443 Network net = osNetworkAdminService.network(osSubnet.getNetworkId());
Daniel Park51f9d1e2018-10-26 13:39:09 +0900444 Set<Subnet> routableSubnets = routableSubnets(osRouter, osSubnet.getId());
445
Jian Li4d138702018-11-27 17:25:28 +0900446 switch (net.getNetworkType()) {
daniel parkee8700b2017-05-11 15:50:03 +0900447 case VXLAN:
Jian Li4d138702018-11-27 17:25:28 +0900448 setGatewayIcmpForVxlan(osSubnet, srcNatGw, net, routableSubnets, install);
daniel parkee8700b2017-05-11 15:50:03 +0900449 break;
450 case VLAN:
Jian Li4d138702018-11-27 17:25:28 +0900451 setGatewayIcmpForVlan(osSubnet, srcNatGw, net, routableSubnets, install);
daniel parkee8700b2017-05-11 15:50:03 +0900452 break;
453 default:
Jian Li4d138702018-11-27 17:25:28 +0900454 final String error = String.format("%s %s", ERR_UNSUPPORTED_NET_TYPE,
455 net.getNetworkType().toString());
daniel parkee8700b2017-05-11 15:50:03 +0900456 throw new IllegalStateException(error);
457 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900458
459 IpAddress gatewayIp = IpAddress.valueOf(osSubnet.getGateway());
daniel park576969a2018-03-09 07:07:41 +0900460 osNodeService.completeNodes(GATEWAY).forEach(gNode ->
Hyunsun Moon0d457362017-06-27 17:19:41 +0900461 setGatewayIcmpRule(
462 gatewayIp,
463 gNode.intgBridge(),
daniel park576969a2018-03-09 07:07:41 +0900464 install));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900465
466 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
467 log.debug(updateStr + "ICMP to {}", osSubnet.getGateway());
468 }
469
Jian Li4d138702018-11-27 17:25:28 +0900470 private void setGatewayIcmpForVxlan(Subnet osSubnet,
471 OpenstackNode srcNatGw,
472 Network network,
473 Set<Subnet> routableSubnets,
474 boolean install) {
475 osNodeService.completeNodes(COMPUTE).stream()
476 .filter(cNode -> cNode.dataIp() != null)
477 .forEach(cNode -> setRulesToGatewayWithRoutableSubnets(
478 cNode,
479 srcNatGw,
480 network.getProviderSegID(),
481 osSubnet,
482 routableSubnets,
483 NetworkMode.VXLAN,
484 install));
485 }
486
487 private void setGatewayIcmpForVlan(Subnet osSubnet,
488 OpenstackNode srcNatGw,
489 Network network,
490 Set<Subnet> routableSubnets,
491 boolean install) {
492 osNodeService.completeNodes(COMPUTE).stream()
493 .filter(cNode -> cNode.vlanPortNum() != null)
494 .forEach(cNode -> setRulesToGatewayWithRoutableSubnets(
495 cNode,
496 srcNatGw,
497 network.getProviderSegID(),
498 osSubnet,
499 routableSubnets,
500 NetworkMode.VLAN,
501 install));
502 }
503
Hyunsun Moon44aac662017-02-18 02:07:01 +0900504 private void setInternalRoutes(Router osRouter, Subnet updatedSubnet, boolean install) {
Jian Liedc8b762018-03-22 15:42:00 +0900505 Network updatedNetwork = osNetworkAdminService.network(updatedSubnet.getNetworkId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900506 Set<Subnet> routableSubnets = routableSubnets(osRouter, updatedSubnet.getId());
Jian Lib6969502018-10-30 20:38:07 +0900507 String updatedSegmentId = getSegmentId(updatedSubnet);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900508
509 // installs rule from/to my subnet intentionally to fix ICMP failure
510 // to my subnet gateway if no external gateway added to the router
Hyunsun Moon0d457362017-06-27 17:19:41 +0900511 osNodeService.completeNodes(COMPUTE).forEach(cNode -> {
512 setInternalRouterRules(
513 cNode.intgBridge(),
Jian Lib6969502018-10-30 20:38:07 +0900514 updatedSegmentId,
515 updatedSegmentId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900516 IpPrefix.valueOf(updatedSubnet.getCidr()),
517 IpPrefix.valueOf(updatedSubnet.getCidr()),
518 updatedNetwork.getNetworkType(),
519 install
520 );
Hyunsun Moon44aac662017-02-18 02:07:01 +0900521
Hyunsun Moon0d457362017-06-27 17:19:41 +0900522 routableSubnets.forEach(subnet -> {
523 setInternalRouterRules(
524 cNode.intgBridge(),
Jian Lib6969502018-10-30 20:38:07 +0900525 updatedSegmentId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900526 getSegmentId(subnet),
527 IpPrefix.valueOf(updatedSubnet.getCidr()),
528 IpPrefix.valueOf(subnet.getCidr()),
529 updatedNetwork.getNetworkType(),
530 install
531 );
532 setInternalRouterRules(
533 cNode.intgBridge(),
534 getSegmentId(subnet),
Jian Lib6969502018-10-30 20:38:07 +0900535 updatedSegmentId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900536 IpPrefix.valueOf(subnet.getCidr()),
537 IpPrefix.valueOf(updatedSubnet.getCidr()),
538 updatedNetwork.getNetworkType(),
539 install
540 );
541 });
542 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900543
daniel parkee8700b2017-05-11 15:50:03 +0900544
Hyunsun Moon44aac662017-02-18 02:07:01 +0900545 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
546 routableSubnets.forEach(subnet -> log.debug(
547 updateStr + "route between subnet:{} and subnet:{}",
548 subnet.getCidr(),
549 updatedSubnet.getCidr()));
550 }
551
552 private Set<Subnet> routableSubnets(Router osRouter, String osSubnetId) {
553 Set<Subnet> osSubnets = osRouterService.routerInterfaces(osRouter.getId())
554 .stream()
555 .filter(iface -> !Objects.equals(iface.getSubnetId(), osSubnetId))
Jian Liedc8b762018-03-22 15:42:00 +0900556 .map(iface -> osNetworkAdminService.subnet(iface.getSubnetId()))
Hyunsun Moon44aac662017-02-18 02:07:01 +0900557 .collect(Collectors.toSet());
558 return ImmutableSet.copyOf(osSubnets);
559 }
560
daniel parkee8700b2017-05-11 15:50:03 +0900561 private String getSegmentId(Subnet osSubnet) {
Jian Liedc8b762018-03-22 15:42:00 +0900562 return osNetworkAdminService.network(osSubnet.getNetworkId()).getProviderSegID();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900563 }
564
565 private void setGatewayIcmpRule(IpAddress gatewayIp, DeviceId deviceId, boolean install) {
566 TrafficSelector selector = DefaultTrafficSelector.builder()
567 .matchEthType(Ethernet.TYPE_IPV4)
568 .matchIPProtocol(IPv4.PROTOCOL_ICMP)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900569 .matchIPDst(gatewayIp.getIp4Address().toIpPrefix())
Hyunsun Moon44aac662017-02-18 02:07:01 +0900570 .build();
571
572 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Li4d5c5c32018-04-02 16:38:18 +0900573 .punt()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900574 .build();
575
sanghodc375372017-06-08 10:41:30 +0900576 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900577 appId,
578 deviceId,
579 selector,
580 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900581 PRIORITY_ICMP_RULE,
sanghodc375372017-06-08 10:41:30 +0900582 Constants.GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900583 install);
584 }
585
Jian Li4d138702018-11-27 17:25:28 +0900586 private void setInternalRouterRules(DeviceId deviceId, String srcSegId, String dstSegId,
daniel parkee8700b2017-05-11 15:50:03 +0900587 IpPrefix srcSubnet, IpPrefix dstSubnet,
588 NetworkType networkType, boolean install) {
Jian Li4d138702018-11-27 17:25:28 +0900589
daniel parkee8700b2017-05-11 15:50:03 +0900590 switch (networkType) {
591 case VXLAN:
Jian Li4d138702018-11-27 17:25:28 +0900592 setInternalRouterRulesForVxlan(deviceId, srcSegId, dstSegId,
593 srcSubnet, dstSubnet, install);
daniel parkee8700b2017-05-11 15:50:03 +0900594 break;
595 case VLAN:
Jian Li4d138702018-11-27 17:25:28 +0900596 setInternalRouterRulesForVlan(deviceId, srcSegId, dstSegId,
597 srcSubnet, dstSubnet, install);
daniel parkee8700b2017-05-11 15:50:03 +0900598 break;
599 default:
Jian Li4d138702018-11-27 17:25:28 +0900600 final String error = String.format("%s %s", ERR_UNSUPPORTED_NET_TYPE,
601 networkType.toString());
daniel parkee8700b2017-05-11 15:50:03 +0900602 throw new IllegalStateException(error);
603 }
604
Hyunsun Moon44aac662017-02-18 02:07:01 +0900605 }
606
Jian Li4d138702018-11-27 17:25:28 +0900607 private void setInternalRouterRulesForVxlan(DeviceId deviceId,
608 String srcSegmentId,
609 String dstSegmentId,
610 IpPrefix srcSubnet,
611 IpPrefix dstSubnet,
612 boolean install) {
613 TrafficSelector selector;
614 TrafficTreatment treatment;
615 selector = DefaultTrafficSelector.builder()
616 .matchEthType(Ethernet.TYPE_IPV4)
617 .matchTunnelId(Long.parseLong(srcSegmentId))
618 .matchIPSrc(srcSubnet.getIp4Prefix())
619 .matchIPDst(dstSubnet.getIp4Prefix())
620 .build();
621
622 treatment = DefaultTrafficTreatment.builder()
623 .setTunnelId(Long.parseLong(dstSegmentId))
624 .transition(STAT_OUTBOUND_TABLE)
625 .build();
626
627 osFlowRuleService.setRule(
628 appId,
629 deviceId,
630 selector,
631 treatment,
632 PRIORITY_INTERNAL_ROUTING_RULE,
633 ROUTING_TABLE,
634 install);
635
636 selector = DefaultTrafficSelector.builder()
637 .matchEthType(Ethernet.TYPE_IPV4)
638 .matchTunnelId(Long.parseLong(dstSegmentId))
639 .matchIPSrc(srcSubnet.getIp4Prefix())
640 .matchIPDst(dstSubnet.getIp4Prefix())
641 .build();
642
643 treatment = DefaultTrafficTreatment.builder()
644 .setTunnelId(Long.parseLong(dstSegmentId))
645 .transition(STAT_OUTBOUND_TABLE)
646 .build();
647
648 osFlowRuleService.setRule(
649 appId,
650 deviceId,
651 selector,
652 treatment,
653 PRIORITY_INTERNAL_ROUTING_RULE,
654 ROUTING_TABLE,
655 install);
656 }
657
658 private void setInternalRouterRulesForVlan(DeviceId deviceId,
659 String srcSegmentId,
660 String dstSegmentId,
661 IpPrefix srcSubnet,
662 IpPrefix dstSubnet,
663 boolean install) {
664 TrafficSelector selector;
665 TrafficTreatment treatment;
666 selector = DefaultTrafficSelector.builder()
667 .matchEthType(Ethernet.TYPE_IPV4)
668 .matchVlanId(VlanId.vlanId(srcSegmentId))
669 .matchIPSrc(srcSubnet.getIp4Prefix())
670 .matchIPDst(dstSubnet.getIp4Prefix())
671 .build();
672
673 treatment = DefaultTrafficTreatment.builder()
674 .setVlanId(VlanId.vlanId(dstSegmentId))
675 .transition(STAT_OUTBOUND_TABLE)
676 .build();
677
678 osFlowRuleService.setRule(
679 appId,
680 deviceId,
681 selector,
682 treatment,
683 PRIORITY_INTERNAL_ROUTING_RULE,
684 ROUTING_TABLE,
685 install);
686
687 selector = DefaultTrafficSelector.builder()
688 .matchEthType(Ethernet.TYPE_IPV4)
689 .matchVlanId(VlanId.vlanId(dstSegmentId))
690 .matchIPSrc(srcSubnet.getIp4Prefix())
691 .matchIPDst(dstSubnet.getIp4Prefix())
692 .build();
693
694 treatment = DefaultTrafficTreatment.builder()
695 .setVlanId(VlanId.vlanId(dstSegmentId))
696 .transition(STAT_OUTBOUND_TABLE)
697 .build();
698
699 osFlowRuleService.setRule(
700 appId,
701 deviceId,
702 selector,
703 treatment,
704 PRIORITY_INTERNAL_ROUTING_RULE,
705 ROUTING_TABLE,
706 install);
707 }
708
Hyunsun Moon0d457362017-06-27 17:19:41 +0900709 private void setRulesToGateway(OpenstackNode osNode, String segmentId, IpPrefix srcSubnet,
daniel parkee8700b2017-05-11 15:50:03 +0900710 NetworkType networkType, boolean install) {
daniel parkb5817102018-02-15 00:18:51 +0900711 OpenstackNode sourceNatGateway = osNodeService.completeNodes(GATEWAY).stream().findFirst().orElse(null);
712
713 if (sourceNatGateway == null) {
714 return;
715 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900716
daniel parkee8700b2017-05-11 15:50:03 +0900717 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
718 .matchEthType(Ethernet.TYPE_IPV4)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900719 .matchIPSrc(srcSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900720 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
721
722 switch (networkType) {
723 case VXLAN:
724 sBuilder.matchTunnelId(Long.parseLong(segmentId));
daniel parkee8700b2017-05-11 15:50:03 +0900725 break;
726 case VLAN:
727 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
daniel parkee8700b2017-05-11 15:50:03 +0900728 break;
729 default:
Jian Li71670d12018-03-02 21:31:07 +0900730 final String error = String.format("%s %s",
731 ERR_UNSUPPORTED_NET_TYPE,
daniel parkee8700b2017-05-11 15:50:03 +0900732 networkType.toString());
733 throw new IllegalStateException(error);
734 }
735
Daniel Parkc64b4c62018-05-09 18:13:39 +0900736 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
737
738 switch (networkType) {
739 case VXLAN:
740 tBuilder.extension(buildExtension(
741 deviceService,
742 osNode.intgBridge(),
743 sourceNatGateway.dataIp().getIp4Address()),
744 osNode.intgBridge())
745 .setOutput(osNode.tunnelPortNum());
746 break;
747
748 case VLAN:
749 tBuilder.setOutput(osNode.vlanPortNum());
750 break;
751
752 default:
753 break;
754 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900755
sanghodc375372017-06-08 10:41:30 +0900756 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900757 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900758 osNode.intgBridge(),
daniel parkee8700b2017-05-11 15:50:03 +0900759 sBuilder.build(),
Daniel Parkc64b4c62018-05-09 18:13:39 +0900760 tBuilder.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900761 PRIORITY_EXTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900762 ROUTING_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900763 install);
764 }
765
sangho072c4dd2017-05-17 10:45:21 +0900766 private void setRulesForSnatIngressRule(DeviceId deviceId, Long vni, IpPrefix destVmIp,
767 DeviceId dstDeviceId, boolean install) {
768
769 TrafficSelector selector = DefaultTrafficSelector.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900770 .matchEthType(Ethernet.TYPE_IPV4)
sangho072c4dd2017-05-17 10:45:21 +0900771 .matchIPDst(destVmIp)
772 .build();
Hyunsun Moon0d457362017-06-27 17:19:41 +0900773
sangho072c4dd2017-05-17 10:45:21 +0900774 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
775 .setTunnelId(vni)
776 .extension(buildExtension(
777 deviceService,
778 deviceId,
779 osNodeService.node(dstDeviceId).dataIp().getIp4Address()),
780 deviceId)
781 .setOutput(osNodeService.node(deviceId).tunnelPortNum())
782 .build();
daniel parkee8700b2017-05-11 15:50:03 +0900783
sanghodc375372017-06-08 10:41:30 +0900784 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900785 appId,
sangho072c4dd2017-05-17 10:45:21 +0900786 deviceId,
787 selector,
788 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900789 PRIORITY_EXTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900790 Constants.GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900791 install);
792 }
793
Daniel Park51f9d1e2018-10-26 13:39:09 +0900794 private void setRulesToGatewayWithRoutableSubnets(OpenstackNode osNode, OpenstackNode sourceNatGateway,
795 String segmentId, Subnet updatedSubnet,
796 Set<Subnet> routableSubnets, NetworkMode networkMode,
797 boolean install) {
798 //At first we install flow rules to gateway with segId and gatewayIp of updated subnet
799 setRulesToGatewayWithDstIp(osNode, sourceNatGateway, segmentId, IpAddress.valueOf(updatedSubnet.getGateway()),
800 networkMode, install);
801
802 routableSubnets.forEach(subnet -> {
803 setRulesToGatewayWithDstIp(osNode, sourceNatGateway,
804 segmentId, IpAddress.valueOf(subnet.getGateway()),
805 networkMode, install);
806
807 Network network = osNetworkAdminService.network(subnet.getNetworkId());
808 setRulesToGatewayWithDstIp(osNode, sourceNatGateway,
809 network.getProviderSegID(), IpAddress.valueOf(updatedSubnet.getGateway()),
810 networkMode, install);
811 });
812 }
813
daniel parkb5817102018-02-15 00:18:51 +0900814 private void setRulesToGatewayWithDstIp(OpenstackNode osNode, OpenstackNode sourceNatGateway,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900815 String segmentId, IpAddress dstIp,
816 NetworkMode networkMode, boolean install) {
Daniel Parkc64b4c62018-05-09 18:13:39 +0900817 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
818 .matchEthType(Ethernet.TYPE_IPV4)
819 .matchIPDst(dstIp.getIp4Address().toIpPrefix());
820
Daniel Parkc64b4c62018-05-09 18:13:39 +0900821 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
822
823 switch (networkMode) {
824 case VXLAN:
Daniel Park51f9d1e2018-10-26 13:39:09 +0900825 sBuilder.matchTunnelId(Long.parseLong(segmentId));
Daniel Parkc64b4c62018-05-09 18:13:39 +0900826 tBuilder.extension(buildExtension(
daniel parkb5817102018-02-15 00:18:51 +0900827 deviceService,
828 osNode.intgBridge(),
829 sourceNatGateway.dataIp().getIp4Address()),
830 osNode.intgBridge())
Daniel Parkc64b4c62018-05-09 18:13:39 +0900831 .setOutput(osNode.tunnelPortNum());
832 break;
833
834 case VLAN:
Daniel Park51f9d1e2018-10-26 13:39:09 +0900835 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
Daniel Parkc64b4c62018-05-09 18:13:39 +0900836 tBuilder.setOutput(osNode.vlanPortNum());
837 break;
838
839 default:
840 break;
841 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900842
sanghodc375372017-06-08 10:41:30 +0900843 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900844 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900845 osNode.intgBridge(),
Daniel Parkc64b4c62018-05-09 18:13:39 +0900846 sBuilder.build(),
847 tBuilder.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900848 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900849 ROUTING_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900850 install);
851 }
852
sangho072c4dd2017-05-17 10:45:21 +0900853 private void setOvsNatIngressRule(DeviceId deviceId, IpPrefix cidr, MacAddress dstMac, boolean install) {
854
855 TrafficSelector selector = DefaultTrafficSelector.builder()
856 .matchEthType(Ethernet.TYPE_IPV4)
857 .matchIPDst(cidr)
858 .build();
859
Jian Liedc8b762018-03-22 15:42:00 +0900860 ExtensionTreatment natTreatment = RulePopulatorUtil
861 .niciraConnTrackTreatmentBuilder(driverService, deviceId)
sangho072c4dd2017-05-17 10:45:21 +0900862 .commit(false)
863 .natAction(true)
864 .table((short) 0)
865 .build();
866
867 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
868 .setEthDst(dstMac)
869 .extension(natTreatment, deviceId)
870 .build();
871
872 osFlowRuleService.setRule(
873 appId,
874 deviceId,
875 selector,
876 treatment,
sanghoe765ce22017-06-23 17:54:57 +0900877 PRIORITY_STATEFUL_SNAT_RULE,
sangho072c4dd2017-05-17 10:45:21 +0900878 GW_COMMON_TABLE,
879 install);
880 }
881
882 private void setOvsNatEgressRule(DeviceId deviceId, IpAddress natAddress, long vni, PortNumber output,
883 boolean install) {
884
885 TrafficSelector selector = DefaultTrafficSelector.builder()
886 .matchEthType(Ethernet.TYPE_IPV4)
887 .matchEthDst(DEFAULT_GATEWAY_MAC)
888 .matchTunnelId(vni)
889 .build();
890
Jian Liedc8b762018-03-22 15:42:00 +0900891 ExtensionTreatment natTreatment = RulePopulatorUtil
892 .niciraConnTrackTreatmentBuilder(driverService, deviceId)
sangho072c4dd2017-05-17 10:45:21 +0900893 .commit(true)
894 .natAction(true)
895 .natIp(natAddress)
896 .build();
897
898 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
899 .extension(natTreatment, deviceId)
900 .setEthDst(DEFAULT_EXTERNAL_ROUTER_MAC)
901 .setEthSrc(DEFAULT_GATEWAY_MAC)
902 .setOutput(output)
903 .build();
904
905 osFlowRuleService.setRule(
906 appId,
907 deviceId,
908 selector,
909 treatment,
sanghoe765ce22017-06-23 17:54:57 +0900910 PRIORITY_STATEFUL_SNAT_RULE,
sangho072c4dd2017-05-17 10:45:21 +0900911 GW_COMMON_TABLE,
912 install);
913 }
914
sanghoe765ce22017-06-23 17:54:57 +0900915 private void setRulesToController(DeviceId deviceId, String segmentId, IpPrefix srcSubnet,
916 NetworkType networkType, boolean install) {
917 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
918 .matchEthType(Ethernet.TYPE_IPV4)
Daniel Parkc64b4c62018-05-09 18:13:39 +0900919 .matchIPSrc(srcSubnet)
920 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
921
sanghoe765ce22017-06-23 17:54:57 +0900922 switch (networkType) {
923 case VXLAN:
Daniel Parkc64b4c62018-05-09 18:13:39 +0900924 sBuilder.matchTunnelId(Long.parseLong(segmentId));
sanghoe765ce22017-06-23 17:54:57 +0900925 break;
926 case VLAN:
Daniel Parkc64b4c62018-05-09 18:13:39 +0900927 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
sanghoe765ce22017-06-23 17:54:57 +0900928 break;
929 default:
Jian Li71670d12018-03-02 21:31:07 +0900930 final String error = String.format("%s %s",
931 ERR_UNSUPPORTED_NET_TYPE,
sanghoe765ce22017-06-23 17:54:57 +0900932 networkType.toString());
933 throw new IllegalStateException(error);
934 }
935
Daniel Parkc64b4c62018-05-09 18:13:39 +0900936 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
sanghoe765ce22017-06-23 17:54:57 +0900937
938 if (networkType.equals(NetworkType.VLAN)) {
939 tBuilder.popVlan();
940 }
941
Jian Li4d5c5c32018-04-02 16:38:18 +0900942 tBuilder.punt();
sanghoe765ce22017-06-23 17:54:57 +0900943
944 osFlowRuleService.setRule(
945 appId,
946 deviceId,
947 sBuilder.build(),
948 tBuilder.build(),
949 PRIORITY_EXTERNAL_ROUTING_RULE,
950 GW_COMMON_TABLE,
951 install);
sanghoe765ce22017-06-23 17:54:57 +0900952 }
sangho072c4dd2017-05-17 10:45:21 +0900953
Frank Wang245a6822017-06-14 09:51:35 +0800954 private void setRouterAdminRules(String segmentId, NetworkType networkType, boolean install) {
955 TrafficTreatment treatment;
956 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
957 .matchEthType(Ethernet.TYPE_IPV4);
958
959 switch (networkType) {
960 case VXLAN:
961 sBuilder.matchTunnelId(Long.parseLong(segmentId));
962 break;
963 case VLAN:
964 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
965 break;
966 default:
Jian Li71670d12018-03-02 21:31:07 +0900967 final String error = String.format("%s %s",
968 ERR_UNSUPPORTED_NET_TYPE,
Frank Wang245a6822017-06-14 09:51:35 +0800969 networkType.toString());
970 throw new IllegalStateException(error);
971 }
972
973 treatment = DefaultTrafficTreatment.builder()
974 .drop()
975 .build();
976
977 osNodeService.completeNodes().stream()
978 .filter(osNode -> osNode.type() == COMPUTE)
979 .forEach(osNode -> {
980 osFlowRuleService.setRule(
981 appId,
982 osNode.intgBridge(),
983 sBuilder.build(),
984 treatment,
985 PRIORITY_ADMIN_RULE,
986 ROUTING_TABLE,
987 install);
988 });
989 }
990
Hyunsun Moon44aac662017-02-18 02:07:01 +0900991 private class InternalRouterEventListener implements OpenstackRouterListener {
992
Jian Li34220ea2018-11-14 01:30:24 +0900993 private boolean isRelevantHelper() {
994 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900995 }
996
997 // FIXME only one leader in the cluster should process
998 @Override
999 public void event(OpenstackRouterEvent event) {
1000 switch (event.type()) {
1001 case OPENSTACK_ROUTER_CREATED:
Jian Li4d138702018-11-27 17:25:28 +09001002 eventExecutor.execute(() -> processRouterCreation(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +09001003 break;
1004 case OPENSTACK_ROUTER_UPDATED:
Jian Li4d138702018-11-27 17:25:28 +09001005 eventExecutor.execute(() -> processRouterUpdate(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +09001006 break;
1007 case OPENSTACK_ROUTER_REMOVED:
Jian Li4d138702018-11-27 17:25:28 +09001008 eventExecutor.execute(() -> processRouterRemoval(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +09001009 break;
1010 case OPENSTACK_ROUTER_INTERFACE_ADDED:
Jian Li4d138702018-11-27 17:25:28 +09001011 eventExecutor.execute(() -> processRouterIntfCreation(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +09001012 break;
1013 case OPENSTACK_ROUTER_INTERFACE_UPDATED:
Jian Li4d138702018-11-27 17:25:28 +09001014 eventExecutor.execute(() -> processRouterIntfUpdate(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +09001015 break;
1016 case OPENSTACK_ROUTER_INTERFACE_REMOVED:
Jian Li4d138702018-11-27 17:25:28 +09001017 eventExecutor.execute(() -> processRouterIntfRemoval(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +09001018 break;
1019 case OPENSTACK_ROUTER_GATEWAY_ADDED:
Jian Li32b03622018-11-06 17:54:24 +09001020 log.debug("Router external gateway {} added",
1021 event.externalGateway().getNetworkId());
Ray Milkey08932a72018-02-20 15:34:38 -08001022 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +09001023 case OPENSTACK_ROUTER_GATEWAY_REMOVED:
Jian Li32b03622018-11-06 17:54:24 +09001024 log.debug("Router external gateway {} removed",
1025 event.externalGateway().getNetworkId());
Ray Milkey08932a72018-02-20 15:34:38 -08001026 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +09001027 case OPENSTACK_FLOATING_IP_CREATED:
1028 case OPENSTACK_FLOATING_IP_UPDATED:
1029 case OPENSTACK_FLOATING_IP_REMOVED:
1030 case OPENSTACK_FLOATING_IP_ASSOCIATED:
1031 case OPENSTACK_FLOATING_IP_DISASSOCIATED:
1032 default:
1033 // do nothing for the other events
1034 break;
1035 }
1036 }
Jian Li4d138702018-11-27 17:25:28 +09001037
1038 private void processRouterCreation(OpenstackRouterEvent event) {
1039 if (!isRelevantHelper()) {
1040 return;
1041 }
1042
1043 log.debug("Router(name:{}, ID:{}) is created",
1044 event.subject().getName(),
1045 event.subject().getId());
1046
1047 routerUpdated(event.subject());
1048 }
1049
1050 private void processRouterUpdate(OpenstackRouterEvent event) {
1051 if (!isRelevantHelper()) {
1052 return;
1053 }
1054
1055 log.debug("Router(name:{}, ID:{}) is updated",
1056 event.subject().getName(),
1057 event.subject().getId());
1058
1059 routerUpdated(event.subject());
1060 }
1061
1062 private void processRouterRemoval(OpenstackRouterEvent event) {
1063 if (!isRelevantHelper()) {
1064 return;
1065 }
1066
1067 log.debug("Router(name:{}, ID:{}) is removed",
1068 event.subject().getName(),
1069 event.subject().getId());
1070
1071 routerRemove(event.subject());
1072 }
1073
1074 private void processRouterIntfCreation(OpenstackRouterEvent event) {
1075 if (!isRelevantHelper()) {
1076 return;
1077 }
1078
1079 log.debug("Router interface {} added to router {}",
1080 event.routerIface().getPortId(),
1081 event.routerIface().getId());
1082
1083 routerIfaceAdded(event.subject(), event.routerIface());
1084 }
1085
1086 private void processRouterIntfUpdate(OpenstackRouterEvent event) {
1087 log.debug("Router interface {} on {} updated",
1088 event.routerIface().getPortId(),
1089 event.routerIface().getId());
1090 }
1091
1092 private void processRouterIntfRemoval(OpenstackRouterEvent event) {
1093 if (!isRelevantHelper()) {
1094 return;
1095 }
1096
1097 log.debug("Router interface {} removed from router {}",
1098 event.routerIface().getPortId(),
1099 event.routerIface().getId());
1100
1101 routerIfaceRemoved(event.subject(), event.routerIface());
1102 }
Hyunsun Moon44aac662017-02-18 02:07:01 +09001103 }
1104
1105 private class InternalNodeEventListener implements OpenstackNodeListener {
1106
Jian Li34220ea2018-11-14 01:30:24 +09001107 private boolean isRelevantHelper() {
1108 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Hyunsun Moon44aac662017-02-18 02:07:01 +09001109 }
1110
1111 @Override
1112 public void event(OpenstackNodeEvent event) {
1113 OpenstackNode osNode = event.subject();
Hyunsun Moon44aac662017-02-18 02:07:01 +09001114 switch (event.type()) {
Hyunsun Moon0d457362017-06-27 17:19:41 +09001115 case OPENSTACK_NODE_COMPLETE:
1116 case OPENSTACK_NODE_INCOMPLETE:
Daniel Park6ed9cf02018-06-27 19:07:44 +09001117 case OPENSTACK_NODE_UPDATED:
1118 case OPENSTACK_NODE_REMOVED:
Hyunsun Moon44aac662017-02-18 02:07:01 +09001119 eventExecutor.execute(() -> {
Jian Li34220ea2018-11-14 01:30:24 +09001120 if (!isRelevantHelper()) {
1121 return;
1122 }
Jian Li4d138702018-11-27 17:25:28 +09001123 reconfigureRouters(osNode);
Hyunsun Moon44aac662017-02-18 02:07:01 +09001124 });
1125 break;
Hyunsun Moon0d457362017-06-27 17:19:41 +09001126 case OPENSTACK_NODE_CREATED:
Hyunsun Moon44aac662017-02-18 02:07:01 +09001127 default:
1128 break;
1129 }
1130 }
1131
Jian Li4d138702018-11-27 17:25:28 +09001132 private void reconfigureRouters(OpenstackNode osNode) {
Hyunsun Moon44aac662017-02-18 02:07:01 +09001133 osRouterService.routers().forEach(osRouter -> {
1134 routerUpdated(osRouter);
1135 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
1136 routerIfaceAdded(osRouter, iface);
1137 });
1138 });
Jian Li4d138702018-11-27 17:25:28 +09001139 log.info("Reconfigure routers for {}", osNode.hostname());
Hyunsun Moon44aac662017-02-18 02:07:01 +09001140 }
1141 }
sangho072c4dd2017-05-17 10:45:21 +09001142
1143 private class InternalInstancePortListener implements InstancePortListener {
1144
Jian Li34220ea2018-11-14 01:30:24 +09001145 private boolean isRelevantHelper(InstancePortEvent event) {
1146 return mastershipService.isLocalMaster(event.subject().deviceId());
sangho072c4dd2017-05-17 10:45:21 +09001147 }
1148
1149 @Override
1150 public void event(InstancePortEvent event) {
1151 InstancePort instPort = event.subject();
1152 switch (event.type()) {
sangho072c4dd2017-05-17 10:45:21 +09001153 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Liec5c32b2018-07-13 14:28:58 +09001154 case OPENSTACK_INSTANCE_PORT_UPDATED:
Jian Li4d138702018-11-27 17:25:28 +09001155 eventExecutor.execute(() ->
1156 processInstancePortDetection(event, instPort));
sangho072c4dd2017-05-17 10:45:21 +09001157 break;
1158 case OPENSTACK_INSTANCE_PORT_VANISHED:
Jian Li4d138702018-11-27 17:25:28 +09001159 eventExecutor.execute(() ->
1160 processInstancePortRemoval(event, instPort));
Jian Liec5c32b2018-07-13 14:28:58 +09001161 break;
1162 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
Jian Li4d138702018-11-27 17:25:28 +09001163 eventExecutor.execute(() ->
1164 processInstanceMigrationStart(event, instPort));
sangho072c4dd2017-05-17 10:45:21 +09001165 break;
Jian Li24ec59f2018-05-23 19:01:25 +09001166 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
Jian Li4d138702018-11-27 17:25:28 +09001167 eventExecutor.execute(() ->
1168 processInstanceMigrationEnd(event, instPort));
Jian Li24ec59f2018-05-23 19:01:25 +09001169 break;
sangho072c4dd2017-05-17 10:45:21 +09001170 default:
1171 break;
1172 }
1173 }
1174
Jian Li4d138702018-11-27 17:25:28 +09001175 private void processInstancePortDetection(InstancePortEvent event,
1176 InstancePort instPort) {
1177 if (!isRelevantHelper(event)) {
1178 return;
1179 }
1180
1181 log.info("RoutingHandler: Instance port detected MAC:{} IP:{}",
1182 instPort.macAddress(),
1183 instPort.ipAddress());
1184
1185 instPortDetected(event.subject());
1186 }
1187
1188 private void processInstancePortRemoval(InstancePortEvent event,
1189 InstancePort instPort) {
1190 if (!isRelevantHelper(event)) {
1191 return;
1192 }
1193
1194 log.info("RoutingHandler: Instance port vanished MAC:{} IP:{}",
1195 instPort.macAddress(),
1196 instPort.ipAddress());
1197
1198 instPortRemoved(event.subject());
1199 }
1200
1201 private void processInstanceMigrationStart(InstancePortEvent event,
1202 InstancePort instPort) {
1203 if (!isRelevantHelper(event)) {
1204 return;
1205 }
1206
1207 log.info("RoutingHandler: Migration started for MAC:{} IP:{}",
1208 instPort.macAddress(),
1209 instPort.ipAddress());
1210
1211 instPortDetected(instPort);
1212 }
1213
1214 private void processInstanceMigrationEnd(InstancePortEvent event,
1215 InstancePort instPort) {
1216 log.info("RoutingHandler: Migration finished for MAC:{} IP:{}",
1217 instPort.macAddress(),
1218 instPort.ipAddress());
1219 // TODO: need to reconfigure rules to point to update VM
1220 }
1221
sangho072c4dd2017-05-17 10:45:21 +09001222 private void instPortDetected(InstancePort instPort) {
Jian Li4d138702018-11-27 17:25:28 +09001223 Network network = osNetworkAdminService.network(instPort.networkId());
1224 if (network.getNetworkType() == FLAT) {
daniel park796c2eb2018-03-22 17:01:51 +09001225 return;
1226 }
Daniel Parkc64b4c62018-05-09 18:13:39 +09001227
1228 if (useStatefulSnat) {
1229 osNodeService.completeNodes(GATEWAY)
1230 .forEach(gwNode -> setRulesForSnatIngressRule(
1231 gwNode.intgBridge(),
Jian Li4d138702018-11-27 17:25:28 +09001232 Long.parseLong(network.getProviderSegID()),
1233 IpPrefix.valueOf(instPort.ipAddress(), VM_PREFIX),
Daniel Parkc64b4c62018-05-09 18:13:39 +09001234 instPort.deviceId(), true));
1235 }
sangho072c4dd2017-05-17 10:45:21 +09001236 }
1237
1238 private void instPortRemoved(InstancePort instPort) {
Jian Li4d138702018-11-27 17:25:28 +09001239 Network network = osNetworkAdminService.network(instPort.networkId());
1240 if (network.getNetworkType() == FLAT) {
daniel park796c2eb2018-03-22 17:01:51 +09001241 return;
1242 }
Daniel Parkc64b4c62018-05-09 18:13:39 +09001243
1244 if (useStatefulSnat) {
1245 osNodeService.completeNodes(GATEWAY)
1246 .forEach(gwNode -> setRulesForSnatIngressRule(
1247 gwNode.intgBridge(),
Jian Li4d138702018-11-27 17:25:28 +09001248 Long.parseLong(network.getProviderSegID()),
1249 IpPrefix.valueOf(instPort.ipAddress(), VM_PREFIX),
Daniel Parkc64b4c62018-05-09 18:13:39 +09001250 instPort.deviceId(), false));
1251 }
sangho072c4dd2017-05-17 10:45:21 +09001252 }
1253 }
Hyunsun Moon44aac662017-02-18 02:07:01 +09001254}