blob: a76961b7e7f3f0ee7f3d5b41586586a087f3a6d7 [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
Ray Milkey8e406512018-10-24 15:56:50 -0700123 /** Use Stateful SNAT for source NATing. */
124 private boolean useStatefulSnat = USE_STATEFUL_SNAT_DEFAULT;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900125
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700126 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900127 protected CoreService coreService;
128
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700129 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900130 protected LeadershipService leadershipService;
131
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700132 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900133 protected ClusterService clusterService;
134
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700135 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900136 protected OpenstackNodeService osNodeService;
137
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700138 @Reference(cardinality = ReferenceCardinality.MANDATORY)
daniel park32b42202018-03-14 16:53:44 +0900139 protected OpenstackNetworkAdminService osNetworkAdminService;
140
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700141 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900142 protected OpenstackRouterService osRouterService;
143
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700144 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho072c4dd2017-05-17 10:45:21 +0900145 protected InstancePortService instancePortService;
146
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700147 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho072c4dd2017-05-17 10:45:21 +0900148 protected DeviceService deviceService;
149
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700150 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sanghodc375372017-06-08 10:41:30 +0900151 protected OpenstackFlowRuleService osFlowRuleService;
152
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700153 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho072c4dd2017-05-17 10:45:21 +0900154 protected MastershipService mastershipService;
155
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700156 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho072c4dd2017-05-17 10:45:21 +0900157 protected DriverService driverService;
158
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700159 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sanghoe765ce22017-06-23 17:54:57 +0900160 protected ComponentConfigService configService;
161
Hyunsun Moon44aac662017-02-18 02:07:01 +0900162 private final ExecutorService eventExecutor = newSingleThreadScheduledExecutor(
163 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
164 private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
165 private final OpenstackRouterListener osRouterListener = new InternalRouterEventListener();
sangho072c4dd2017-05-17 10:45:21 +0900166 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900167
168 private ApplicationId appId;
169 private NodeId localNodeId;
170
171 @Activate
172 protected void activate() {
173 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
174 localNodeId = clusterService.getLocalNode().id();
175 leadershipService.runForLeadership(appId.name());
176 osNodeService.addListener(osNodeListener);
177 osRouterService.addListener(osRouterListener);
sangho072c4dd2017-05-17 10:45:21 +0900178 instancePortService.addListener(instancePortListener);
sanghoe765ce22017-06-23 17:54:57 +0900179 configService.registerProperties(getClass());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900180
181 log.info("Started");
182 }
183
184 @Deactivate
185 protected void deactivate() {
186 osRouterService.removeListener(osRouterListener);
187 osNodeService.removeListener(osNodeListener);
sangho072c4dd2017-05-17 10:45:21 +0900188 instancePortService.removeListener(instancePortListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900189 leadershipService.withdraw(appId.name());
sanghoe765ce22017-06-23 17:54:57 +0900190 configService.unregisterProperties(getClass(), false);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900191 eventExecutor.shutdown();
192
193 log.info("Stopped");
194 }
195
sanghoe765ce22017-06-23 17:54:57 +0900196 @Modified
197 protected void modified(ComponentContext context) {
198 Dictionary<?, ?> properties = context.getProperties();
199 Boolean flag;
200
Ray Milkey8e406512018-10-24 15:56:50 -0700201 flag = Tools.isPropertyEnabled(properties, USE_STATEFUL_SNAT);
sanghoe765ce22017-06-23 17:54:57 +0900202 if (flag == null) {
203 log.info("useStatefulSnat is not configured, " +
204 "using current value of {}", useStatefulSnat);
205 } else {
206 useStatefulSnat = flag;
207 log.info("Configured. useStatefulSnat is {}",
208 useStatefulSnat ? "enabled" : "disabled");
209 }
210
211 resetSnatRules();
212 }
213
Hyunsun Moon44aac662017-02-18 02:07:01 +0900214 private void routerUpdated(Router osRouter) {
215 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
Frank Wang245a6822017-06-14 09:51:35 +0800216 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
Jian Liedc8b762018-03-22 15:42:00 +0900217 Network network = osNetworkAdminService.network(osNetworkAdminService.subnet(iface.getSubnetId())
Frank Wang245a6822017-06-14 09:51:35 +0800218 .getNetworkId());
219 setRouterAdminRules(network.getProviderSegID(), network.getNetworkType(), !osRouter.isAdminStateUp());
220 });
221
Jian Liedc8b762018-03-22 15:42:00 +0900222 ExternalPeerRouter externalPeerRouter = osNetworkAdminService.externalPeerRouter(exGateway);
Jian Li5e2ad4a2018-07-16 13:40:53 +0900223 VlanId vlanId = externalPeerRouter == null ? VlanId.NONE : externalPeerRouter.vlanId();
daniel park576969a2018-03-09 07:07:41 +0900224
Hyunsun Moon44aac662017-02-18 02:07:01 +0900225 if (exGateway == null) {
Daniel Park613ac372018-06-28 14:30:11 +0900226 deleteUnassociatedExternalPeerRouter();
daniel park576969a2018-03-09 07:07:41 +0900227 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> setSourceNat(iface, false));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900228 } else {
daniel park32b42202018-03-14 16:53:44 +0900229 osNetworkAdminService.deriveExternalPeerRouterMac(exGateway, osRouter, vlanId);
daniel park576969a2018-03-09 07:07:41 +0900230 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface ->
231 setSourceNat(iface, exGateway.isEnableSnat()));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900232 }
233 }
234
Daniel Park613ac372018-06-28 14:30:11 +0900235 private void deleteUnassociatedExternalPeerRouter() {
236 log.trace("Deleting unassociated external peer router");
237
238 try {
239 Set<String> routerIps = Sets.newConcurrentHashSet();
240
241 osRouterService.routers().stream()
242 .filter(router -> getGatewayIpAddress(router) != null)
243 .map(router -> getGatewayIpAddress(router).toString())
244 .forEach(routerIps::add);
245
246 osNetworkAdminService.externalPeerRouters().stream()
247 .filter(externalPeerRouter ->
Jian Li5e2ad4a2018-07-16 13:40:53 +0900248 !routerIps.contains(externalPeerRouter.ipAddress().toString()))
Daniel Park613ac372018-06-28 14:30:11 +0900249 .forEach(externalPeerRouter -> {
250 osNetworkAdminService
Jian Li5e2ad4a2018-07-16 13:40:53 +0900251 .deleteExternalPeerRouter(externalPeerRouter.ipAddress().toString());
Daniel Park613ac372018-06-28 14:30:11 +0900252 log.trace("Deleted unassociated external peer router {}",
Jian Li5e2ad4a2018-07-16 13:40:53 +0900253 externalPeerRouter.ipAddress().toString());
Daniel Park613ac372018-06-28 14:30:11 +0900254 });
255 } catch (Exception e) {
256 log.error("Exception occurred because of {}", e.toString());
257 }
258 }
259
Frank Wang245a6822017-06-14 09:51:35 +0800260 private void routerRemove(Router osRouter) {
261 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
Jian Liedc8b762018-03-22 15:42:00 +0900262 Network network = osNetworkAdminService.network(osNetworkAdminService.subnet(iface.getSubnetId())
Frank Wang245a6822017-06-14 09:51:35 +0800263 .getNetworkId());
264 setRouterAdminRules(network.getProviderSegID(), network.getNetworkType(), false);
265 });
266 }
267
Hyunsun Moon44aac662017-02-18 02:07:01 +0900268 private void routerIfaceAdded(Router osRouter, RouterInterface osRouterIface) {
Jian Liedc8b762018-03-22 15:42:00 +0900269 Subnet osSubnet = osNetworkAdminService.subnet(osRouterIface.getSubnetId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900270 if (osSubnet == null) {
271 final String error = String.format(
Jian Li71670d12018-03-02 21:31:07 +0900272 "Failed to set flows for router %s: subnet %s does not exist",
Hyunsun Moon44aac662017-02-18 02:07:01 +0900273 osRouterIface.getId(),
274 osRouterIface.getSubnetId());
275 throw new IllegalStateException(error);
276 }
Frank Wang245a6822017-06-14 09:51:35 +0800277
278 if (!osRouter.isAdminStateUp()) {
Jian Liedc8b762018-03-22 15:42:00 +0900279 Network network = osNetworkAdminService.network(osSubnet.getNetworkId());
Frank Wang245a6822017-06-14 09:51:35 +0800280 setRouterAdminRules(network.getProviderSegID(), network.getNetworkType(), true);
281 }
282
Hyunsun Moon44aac662017-02-18 02:07:01 +0900283 setInternalRoutes(osRouter, osSubnet, true);
Daniel Park51f9d1e2018-10-26 13:39:09 +0900284 setGatewayIcmp(osSubnet, osRouter, true);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900285 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
286 if (exGateway != null && exGateway.isEnableSnat()) {
daniel park576969a2018-03-09 07:07:41 +0900287 setSourceNat(osRouterIface, true);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900288 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900289 log.info("Connected subnet({}) to {}", osSubnet.getCidr(), osRouter.getName());
290 }
291
292 private void routerIfaceRemoved(Router osRouter, RouterInterface osRouterIface) {
Jian Liedc8b762018-03-22 15:42:00 +0900293 Subnet osSubnet = osNetworkAdminService.subnet(osRouterIface.getSubnetId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900294 if (osSubnet == null) {
295 final String error = String.format(
Jian Li71670d12018-03-02 21:31:07 +0900296 "Failed to set flows for router %s: subnet %s does not exist",
Hyunsun Moon44aac662017-02-18 02:07:01 +0900297 osRouterIface.getId(),
298 osRouterIface.getSubnetId());
299 throw new IllegalStateException(error);
300 }
301
Frank Wang245a6822017-06-14 09:51:35 +0800302 if (!osRouter.isAdminStateUp()) {
Jian Liedc8b762018-03-22 15:42:00 +0900303 Network network = osNetworkAdminService.network(osSubnet.getNetworkId());
Frank Wang245a6822017-06-14 09:51:35 +0800304 setRouterAdminRules(network.getProviderSegID(), network.getNetworkType(), false);
305 }
306
Hyunsun Moon44aac662017-02-18 02:07:01 +0900307 setInternalRoutes(osRouter, osSubnet, false);
Daniel Park51f9d1e2018-10-26 13:39:09 +0900308 setGatewayIcmp(osSubnet, osRouter, false);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900309 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
310 if (exGateway != null && exGateway.isEnableSnat()) {
daniel park576969a2018-03-09 07:07:41 +0900311 setSourceNat(osRouterIface, false);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900312 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900313 log.info("Disconnected subnet({}) from {}", osSubnet.getCidr(), osRouter.getName());
314 }
315
daniel park576969a2018-03-09 07:07:41 +0900316 private void setSourceNat(RouterInterface routerIface, boolean install) {
Jian Liedc8b762018-03-22 15:42:00 +0900317 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
318 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900319
Hyunsun Moon0d457362017-06-27 17:19:41 +0900320 osNodeService.completeNodes(COMPUTE).forEach(cNode -> {
321 setRulesToGateway(cNode, osNet.getProviderSegID(),
322 IpPrefix.valueOf(osSubnet.getCidr()), osNet.getNetworkType(),
323 install);
324 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900325
sanghoe765ce22017-06-23 17:54:57 +0900326 if (useStatefulSnat) {
327 setStatefulSnatRules(routerIface, install);
328 } else {
329 setReactiveSnatRules(routerIface, install);
330 }
331
332 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
333 log.info(updateStr + "external access for subnet({})", osSubnet.getCidr());
334 }
335
336 private void setStatefulSnatRules(RouterInterface routerIface, boolean install) {
Jian Liedc8b762018-03-22 15:42:00 +0900337 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
338 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
sanghoe765ce22017-06-23 17:54:57 +0900339
Jian Li32b03622018-11-06 17:54:24 +0900340 if (osNet.getNetworkType() == FLAT) {
daniel park796c2eb2018-03-22 17:01:51 +0900341 return;
342 }
343
sanghoe765ce22017-06-23 17:54:57 +0900344 Optional<Router> osRouter = osRouterService.routers().stream()
345 .filter(router -> osRouterService.routerInterfaces(routerIface.getId()) != null)
346 .findAny();
347
348 if (!osRouter.isPresent()) {
349 log.error("Cannot find a router for router interface {} ", routerIface);
350 return;
351 }
352 IpAddress natAddress = getGatewayIpAddress(osRouter.get());
sangho072c4dd2017-05-17 10:45:21 +0900353 if (natAddress == null) {
354 return;
355 }
Jian Liedc8b762018-03-22 15:42:00 +0900356 String netId = osNetworkAdminService.subnet(routerIface.getSubnetId()).getNetworkId();
sangho072c4dd2017-05-17 10:45:21 +0900357
358 osNodeService.completeNodes(OpenstackNode.NodeType.GATEWAY)
359 .forEach(gwNode -> {
daniel park576969a2018-03-09 07:07:41 +0900360 instancePortService.instancePorts(netId)
Jian Lic2403592018-07-18 12:56:45 +0900361 .stream()
362 .filter(port -> port.state() == ACTIVE)
daniel park576969a2018-03-09 07:07:41 +0900363 .forEach(port -> setRulesForSnatIngressRule(gwNode.intgBridge(),
sangho072c4dd2017-05-17 10:45:21 +0900364 Long.parseLong(osNet.getProviderSegID()),
365 IpPrefix.valueOf(port.ipAddress(), 32),
366 port.deviceId(),
367 install));
368
369 setOvsNatIngressRule(gwNode.intgBridge(),
370 IpPrefix.valueOf(natAddress, 32),
371 Constants.DEFAULT_EXTERNAL_ROUTER_MAC, install);
372 setOvsNatEgressRule(gwNode.intgBridge(),
373 natAddress, Long.parseLong(osNet.getProviderSegID()),
374 gwNode.patchPortNum(), install);
375 });
sanghoe765ce22017-06-23 17:54:57 +0900376 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900377
sanghoe765ce22017-06-23 17:54:57 +0900378 private void setReactiveSnatRules(RouterInterface routerIface, boolean install) {
Jian Liedc8b762018-03-22 15:42:00 +0900379 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
380 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
sanghoe765ce22017-06-23 17:54:57 +0900381
382 osNodeService.completeNodes(GATEWAY)
383 .forEach(gwNode -> setRulesToController(
384 gwNode.intgBridge(),
385 osNet.getProviderSegID(),
386 IpPrefix.valueOf(osSubnet.getCidr()),
387 osNet.getNetworkType(),
388 install));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900389 }
390
sangho072c4dd2017-05-17 10:45:21 +0900391 private IpAddress getGatewayIpAddress(Router osRouter) {
392
Daniel Park613ac372018-06-28 14:30:11 +0900393 if (osRouter.getExternalGatewayInfo() == null) {
394 return null;
395 }
Jian Liedc8b762018-03-22 15:42:00 +0900396 String extNetId = osNetworkAdminService.network(osRouter.getExternalGatewayInfo().getNetworkId()).getId();
397 Optional<Subnet> extSubnet = osNetworkAdminService.subnets().stream()
sangho072c4dd2017-05-17 10:45:21 +0900398 .filter(subnet -> subnet.getNetworkId().equals(extNetId))
399 .findAny();
400
401 if (!extSubnet.isPresent()) {
402 log.error("Cannot find externel subnet for the router");
403 return null;
404 }
405
406 return IpAddress.valueOf(extSubnet.get().getGateway());
407 }
408
sanghoe765ce22017-06-23 17:54:57 +0900409 private void resetSnatRules() {
410 if (useStatefulSnat) {
411 osRouterService.routerInterfaces().forEach(
412 routerIface -> {
413 setReactiveSnatRules(routerIface, false);
414 setStatefulSnatRules(routerIface, true);
415 }
416 );
417 } else {
418 osRouterService.routerInterfaces().forEach(
419 routerIface -> {
420 setStatefulSnatRules(routerIface, false);
421 setReactiveSnatRules(routerIface, true);
422 }
423 );
424 }
425 }
426
Daniel Park51f9d1e2018-10-26 13:39:09 +0900427 private void setGatewayIcmp(Subnet osSubnet, Router osRouter, boolean install) {
daniel parkb5817102018-02-15 00:18:51 +0900428 OpenstackNode sourceNatGateway = osNodeService.completeNodes(GATEWAY).stream().findFirst().orElse(null);
429
430 if (sourceNatGateway == null) {
431 return;
432 }
433
Hyunsun Moon44aac662017-02-18 02:07:01 +0900434 if (Strings.isNullOrEmpty(osSubnet.getGateway())) {
435 // do nothing if no gateway is set
436 return;
437 }
438
439 // take ICMP request to a subnet gateway through gateway node group
Jian Liedc8b762018-03-22 15:42:00 +0900440 Network network = osNetworkAdminService.network(osSubnet.getNetworkId());
Daniel Park51f9d1e2018-10-26 13:39:09 +0900441 Set<Subnet> routableSubnets = routableSubnets(osRouter, osSubnet.getId());
442
daniel parkee8700b2017-05-11 15:50:03 +0900443 switch (network.getNetworkType()) {
444 case VXLAN:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900445 osNodeService.completeNodes(COMPUTE).stream()
446 .filter(cNode -> cNode.dataIp() != null)
Daniel Park51f9d1e2018-10-26 13:39:09 +0900447 .forEach(cNode -> setRulesToGatewayWithRoutableSubnets(
Hyunsun Moon0d457362017-06-27 17:19:41 +0900448 cNode,
daniel parkb5817102018-02-15 00:18:51 +0900449 sourceNatGateway,
daniel parkee8700b2017-05-11 15:50:03 +0900450 network.getProviderSegID(),
Daniel Park51f9d1e2018-10-26 13:39:09 +0900451 osSubnet,
452 routableSubnets,
daniel parkee8700b2017-05-11 15:50:03 +0900453 NetworkMode.VXLAN,
454 install));
455 break;
456 case VLAN:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900457 osNodeService.completeNodes(COMPUTE).stream()
458 .filter(cNode -> cNode.vlanPortNum() != null)
Daniel Park51f9d1e2018-10-26 13:39:09 +0900459 .forEach(cNode -> setRulesToGatewayWithRoutableSubnets(
Hyunsun Moon0d457362017-06-27 17:19:41 +0900460 cNode,
daniel parkb5817102018-02-15 00:18:51 +0900461 sourceNatGateway,
daniel parkee8700b2017-05-11 15:50:03 +0900462 network.getProviderSegID(),
Daniel Park51f9d1e2018-10-26 13:39:09 +0900463 osSubnet,
464 routableSubnets,
daniel parkee8700b2017-05-11 15:50:03 +0900465 NetworkMode.VLAN,
466 install));
467 break;
468 default:
Jian Li71670d12018-03-02 21:31:07 +0900469 final String error = String.format("%s %s",
470 ERR_UNSUPPORTED_NET_TYPE,
daniel parkee8700b2017-05-11 15:50:03 +0900471 network.getNetworkType().toString());
472 throw new IllegalStateException(error);
473 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900474
475 IpAddress gatewayIp = IpAddress.valueOf(osSubnet.getGateway());
daniel park576969a2018-03-09 07:07:41 +0900476 osNodeService.completeNodes(GATEWAY).forEach(gNode ->
Hyunsun Moon0d457362017-06-27 17:19:41 +0900477 setGatewayIcmpRule(
478 gatewayIp,
479 gNode.intgBridge(),
daniel park576969a2018-03-09 07:07:41 +0900480 install));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900481
482 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
483 log.debug(updateStr + "ICMP to {}", osSubnet.getGateway());
484 }
485
486 private void setInternalRoutes(Router osRouter, Subnet updatedSubnet, boolean install) {
Jian Liedc8b762018-03-22 15:42:00 +0900487 Network updatedNetwork = osNetworkAdminService.network(updatedSubnet.getNetworkId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900488 Set<Subnet> routableSubnets = routableSubnets(osRouter, updatedSubnet.getId());
Jian Lib6969502018-10-30 20:38:07 +0900489 String updatedSegmentId = getSegmentId(updatedSubnet);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900490
491 // installs rule from/to my subnet intentionally to fix ICMP failure
492 // to my subnet gateway if no external gateway added to the router
Hyunsun Moon0d457362017-06-27 17:19:41 +0900493 osNodeService.completeNodes(COMPUTE).forEach(cNode -> {
494 setInternalRouterRules(
495 cNode.intgBridge(),
Jian Lib6969502018-10-30 20:38:07 +0900496 updatedSegmentId,
497 updatedSegmentId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900498 IpPrefix.valueOf(updatedSubnet.getCidr()),
499 IpPrefix.valueOf(updatedSubnet.getCidr()),
500 updatedNetwork.getNetworkType(),
501 install
502 );
Hyunsun Moon44aac662017-02-18 02:07:01 +0900503
Hyunsun Moon0d457362017-06-27 17:19:41 +0900504 routableSubnets.forEach(subnet -> {
505 setInternalRouterRules(
506 cNode.intgBridge(),
Jian Lib6969502018-10-30 20:38:07 +0900507 updatedSegmentId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900508 getSegmentId(subnet),
509 IpPrefix.valueOf(updatedSubnet.getCidr()),
510 IpPrefix.valueOf(subnet.getCidr()),
511 updatedNetwork.getNetworkType(),
512 install
513 );
514 setInternalRouterRules(
515 cNode.intgBridge(),
516 getSegmentId(subnet),
Jian Lib6969502018-10-30 20:38:07 +0900517 updatedSegmentId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900518 IpPrefix.valueOf(subnet.getCidr()),
519 IpPrefix.valueOf(updatedSubnet.getCidr()),
520 updatedNetwork.getNetworkType(),
521 install
522 );
523 });
524 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900525
daniel parkee8700b2017-05-11 15:50:03 +0900526
Hyunsun Moon44aac662017-02-18 02:07:01 +0900527 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
528 routableSubnets.forEach(subnet -> log.debug(
529 updateStr + "route between subnet:{} and subnet:{}",
530 subnet.getCidr(),
531 updatedSubnet.getCidr()));
532 }
533
534 private Set<Subnet> routableSubnets(Router osRouter, String osSubnetId) {
535 Set<Subnet> osSubnets = osRouterService.routerInterfaces(osRouter.getId())
536 .stream()
537 .filter(iface -> !Objects.equals(iface.getSubnetId(), osSubnetId))
Jian Liedc8b762018-03-22 15:42:00 +0900538 .map(iface -> osNetworkAdminService.subnet(iface.getSubnetId()))
Hyunsun Moon44aac662017-02-18 02:07:01 +0900539 .collect(Collectors.toSet());
540 return ImmutableSet.copyOf(osSubnets);
541 }
542
daniel parkee8700b2017-05-11 15:50:03 +0900543 private String getSegmentId(Subnet osSubnet) {
Jian Liedc8b762018-03-22 15:42:00 +0900544 return osNetworkAdminService.network(osSubnet.getNetworkId()).getProviderSegID();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900545 }
546
547 private void setGatewayIcmpRule(IpAddress gatewayIp, DeviceId deviceId, boolean install) {
548 TrafficSelector selector = DefaultTrafficSelector.builder()
549 .matchEthType(Ethernet.TYPE_IPV4)
550 .matchIPProtocol(IPv4.PROTOCOL_ICMP)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900551 .matchIPDst(gatewayIp.getIp4Address().toIpPrefix())
Hyunsun Moon44aac662017-02-18 02:07:01 +0900552 .build();
553
554 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Li4d5c5c32018-04-02 16:38:18 +0900555 .punt()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900556 .build();
557
sanghodc375372017-06-08 10:41:30 +0900558 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900559 appId,
560 deviceId,
561 selector,
562 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900563 PRIORITY_ICMP_RULE,
sanghodc375372017-06-08 10:41:30 +0900564 Constants.GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900565 install);
566 }
567
daniel parkee8700b2017-05-11 15:50:03 +0900568 private void setInternalRouterRules(DeviceId deviceId, String srcSegmentId, String dstSegmentId,
569 IpPrefix srcSubnet, IpPrefix dstSubnet,
570 NetworkType networkType, boolean install) {
571 TrafficSelector selector;
572 TrafficTreatment treatment;
573 switch (networkType) {
574 case VXLAN:
575 selector = DefaultTrafficSelector.builder()
576 .matchEthType(Ethernet.TYPE_IPV4)
577 .matchTunnelId(Long.parseLong(srcSegmentId))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900578 .matchIPSrc(srcSubnet.getIp4Prefix())
579 .matchIPDst(dstSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900580 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900581
daniel parkee8700b2017-05-11 15:50:03 +0900582 treatment = DefaultTrafficTreatment.builder()
583 .setTunnelId(Long.parseLong(dstSegmentId))
Jian Li8abf2fe2018-06-12 18:42:30 +0900584 .transition(STAT_OUTBOUND_TABLE)
daniel parkee8700b2017-05-11 15:50:03 +0900585 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900586
sanghodc375372017-06-08 10:41:30 +0900587 osFlowRuleService.setRule(
daniel parkee8700b2017-05-11 15:50:03 +0900588 appId,
589 deviceId,
590 selector,
591 treatment,
daniel parkee8700b2017-05-11 15:50:03 +0900592 PRIORITY_INTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900593 ROUTING_TABLE,
daniel parkee8700b2017-05-11 15:50:03 +0900594 install);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900595
daniel parkee8700b2017-05-11 15:50:03 +0900596 selector = DefaultTrafficSelector.builder()
597 .matchEthType(Ethernet.TYPE_IPV4)
598 .matchTunnelId(Long.parseLong(dstSegmentId))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900599 .matchIPSrc(srcSubnet.getIp4Prefix())
600 .matchIPDst(dstSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900601 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900602
daniel parkee8700b2017-05-11 15:50:03 +0900603 treatment = DefaultTrafficTreatment.builder()
604 .setTunnelId(Long.parseLong(dstSegmentId))
Jian Li8abf2fe2018-06-12 18:42:30 +0900605 .transition(STAT_OUTBOUND_TABLE)
daniel parkee8700b2017-05-11 15:50:03 +0900606 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900607
sanghodc375372017-06-08 10:41:30 +0900608 osFlowRuleService.setRule(
daniel parkee8700b2017-05-11 15:50:03 +0900609 appId,
610 deviceId,
611 selector,
612 treatment,
daniel parkee8700b2017-05-11 15:50:03 +0900613 PRIORITY_INTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900614 ROUTING_TABLE,
daniel parkee8700b2017-05-11 15:50:03 +0900615 install);
616 break;
617 case VLAN:
618 selector = DefaultTrafficSelector.builder()
619 .matchEthType(Ethernet.TYPE_IPV4)
620 .matchVlanId(VlanId.vlanId(srcSegmentId))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900621 .matchIPSrc(srcSubnet.getIp4Prefix())
622 .matchIPDst(dstSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900623 .build();
624
625 treatment = DefaultTrafficTreatment.builder()
626 .setVlanId(VlanId.vlanId(dstSegmentId))
Jian Li8abf2fe2018-06-12 18:42:30 +0900627 .transition(STAT_OUTBOUND_TABLE)
daniel parkee8700b2017-05-11 15:50:03 +0900628 .build();
629
sanghodc375372017-06-08 10:41:30 +0900630 osFlowRuleService.setRule(
daniel parkee8700b2017-05-11 15:50:03 +0900631 appId,
632 deviceId,
633 selector,
634 treatment,
daniel parkee8700b2017-05-11 15:50:03 +0900635 PRIORITY_INTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900636 ROUTING_TABLE,
daniel parkee8700b2017-05-11 15:50:03 +0900637 install);
638
639 selector = DefaultTrafficSelector.builder()
640 .matchEthType(Ethernet.TYPE_IPV4)
641 .matchVlanId(VlanId.vlanId(dstSegmentId))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900642 .matchIPSrc(srcSubnet.getIp4Prefix())
643 .matchIPDst(dstSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900644 .build();
645
646 treatment = DefaultTrafficTreatment.builder()
647 .setVlanId(VlanId.vlanId(dstSegmentId))
Jian Li8abf2fe2018-06-12 18:42:30 +0900648 .transition(STAT_OUTBOUND_TABLE)
daniel parkee8700b2017-05-11 15:50:03 +0900649 .build();
650
sanghodc375372017-06-08 10:41:30 +0900651 osFlowRuleService.setRule(
daniel parkee8700b2017-05-11 15:50:03 +0900652 appId,
653 deviceId,
654 selector,
655 treatment,
daniel parkee8700b2017-05-11 15:50:03 +0900656 PRIORITY_INTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900657 ROUTING_TABLE,
daniel parkee8700b2017-05-11 15:50:03 +0900658 install);
659 break;
660 default:
Jian Li71670d12018-03-02 21:31:07 +0900661 final String error = String.format("%s %s",
662 ERR_UNSUPPORTED_NET_TYPE,
daniel parkee8700b2017-05-11 15:50:03 +0900663 networkType.toString());
664 throw new IllegalStateException(error);
665 }
666
Hyunsun Moon44aac662017-02-18 02:07:01 +0900667 }
668
Hyunsun Moon0d457362017-06-27 17:19:41 +0900669 private void setRulesToGateway(OpenstackNode osNode, String segmentId, IpPrefix srcSubnet,
daniel parkee8700b2017-05-11 15:50:03 +0900670 NetworkType networkType, boolean install) {
daniel parkb5817102018-02-15 00:18:51 +0900671 OpenstackNode sourceNatGateway = osNodeService.completeNodes(GATEWAY).stream().findFirst().orElse(null);
672
673 if (sourceNatGateway == null) {
674 return;
675 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900676
daniel parkee8700b2017-05-11 15:50:03 +0900677 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
678 .matchEthType(Ethernet.TYPE_IPV4)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900679 .matchIPSrc(srcSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900680 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
681
682 switch (networkType) {
683 case VXLAN:
684 sBuilder.matchTunnelId(Long.parseLong(segmentId));
daniel parkee8700b2017-05-11 15:50:03 +0900685 break;
686 case VLAN:
687 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
daniel parkee8700b2017-05-11 15:50:03 +0900688 break;
689 default:
Jian Li71670d12018-03-02 21:31:07 +0900690 final String error = String.format("%s %s",
691 ERR_UNSUPPORTED_NET_TYPE,
daniel parkee8700b2017-05-11 15:50:03 +0900692 networkType.toString());
693 throw new IllegalStateException(error);
694 }
695
Daniel Parkc64b4c62018-05-09 18:13:39 +0900696 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
697
698 switch (networkType) {
699 case VXLAN:
700 tBuilder.extension(buildExtension(
701 deviceService,
702 osNode.intgBridge(),
703 sourceNatGateway.dataIp().getIp4Address()),
704 osNode.intgBridge())
705 .setOutput(osNode.tunnelPortNum());
706 break;
707
708 case VLAN:
709 tBuilder.setOutput(osNode.vlanPortNum());
710 break;
711
712 default:
713 break;
714 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900715
sanghodc375372017-06-08 10:41:30 +0900716 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900717 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900718 osNode.intgBridge(),
daniel parkee8700b2017-05-11 15:50:03 +0900719 sBuilder.build(),
Daniel Parkc64b4c62018-05-09 18:13:39 +0900720 tBuilder.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900721 PRIORITY_EXTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900722 ROUTING_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900723 install);
724 }
725
sangho072c4dd2017-05-17 10:45:21 +0900726 private void setRulesForSnatIngressRule(DeviceId deviceId, Long vni, IpPrefix destVmIp,
727 DeviceId dstDeviceId, boolean install) {
728
729 TrafficSelector selector = DefaultTrafficSelector.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900730 .matchEthType(Ethernet.TYPE_IPV4)
sangho072c4dd2017-05-17 10:45:21 +0900731 .matchIPDst(destVmIp)
732 .build();
Hyunsun Moon0d457362017-06-27 17:19:41 +0900733
sangho072c4dd2017-05-17 10:45:21 +0900734 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
735 .setTunnelId(vni)
736 .extension(buildExtension(
737 deviceService,
738 deviceId,
739 osNodeService.node(dstDeviceId).dataIp().getIp4Address()),
740 deviceId)
741 .setOutput(osNodeService.node(deviceId).tunnelPortNum())
742 .build();
daniel parkee8700b2017-05-11 15:50:03 +0900743
sanghodc375372017-06-08 10:41:30 +0900744 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900745 appId,
sangho072c4dd2017-05-17 10:45:21 +0900746 deviceId,
747 selector,
748 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900749 PRIORITY_EXTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900750 Constants.GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900751 install);
752 }
753
Daniel Park51f9d1e2018-10-26 13:39:09 +0900754 private void setRulesToGatewayWithRoutableSubnets(OpenstackNode osNode, OpenstackNode sourceNatGateway,
755 String segmentId, Subnet updatedSubnet,
756 Set<Subnet> routableSubnets, NetworkMode networkMode,
757 boolean install) {
758 //At first we install flow rules to gateway with segId and gatewayIp of updated subnet
759 setRulesToGatewayWithDstIp(osNode, sourceNatGateway, segmentId, IpAddress.valueOf(updatedSubnet.getGateway()),
760 networkMode, install);
761
762 routableSubnets.forEach(subnet -> {
763 setRulesToGatewayWithDstIp(osNode, sourceNatGateway,
764 segmentId, IpAddress.valueOf(subnet.getGateway()),
765 networkMode, install);
766
767 Network network = osNetworkAdminService.network(subnet.getNetworkId());
768 setRulesToGatewayWithDstIp(osNode, sourceNatGateway,
769 network.getProviderSegID(), IpAddress.valueOf(updatedSubnet.getGateway()),
770 networkMode, install);
771 });
772 }
773
daniel parkb5817102018-02-15 00:18:51 +0900774 private void setRulesToGatewayWithDstIp(OpenstackNode osNode, OpenstackNode sourceNatGateway,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900775 String segmentId, IpAddress dstIp,
776 NetworkMode networkMode, boolean install) {
Daniel Parkc64b4c62018-05-09 18:13:39 +0900777 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
778 .matchEthType(Ethernet.TYPE_IPV4)
779 .matchIPDst(dstIp.getIp4Address().toIpPrefix());
780
Daniel Parkc64b4c62018-05-09 18:13:39 +0900781 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
782
783 switch (networkMode) {
784 case VXLAN:
Daniel Park51f9d1e2018-10-26 13:39:09 +0900785 sBuilder.matchTunnelId(Long.parseLong(segmentId));
Daniel Parkc64b4c62018-05-09 18:13:39 +0900786 tBuilder.extension(buildExtension(
daniel parkb5817102018-02-15 00:18:51 +0900787 deviceService,
788 osNode.intgBridge(),
789 sourceNatGateway.dataIp().getIp4Address()),
790 osNode.intgBridge())
Daniel Parkc64b4c62018-05-09 18:13:39 +0900791 .setOutput(osNode.tunnelPortNum());
792 break;
793
794 case VLAN:
Daniel Park51f9d1e2018-10-26 13:39:09 +0900795 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
Daniel Parkc64b4c62018-05-09 18:13:39 +0900796 tBuilder.setOutput(osNode.vlanPortNum());
797 break;
798
799 default:
800 break;
801 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900802
sanghodc375372017-06-08 10:41:30 +0900803 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900804 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900805 osNode.intgBridge(),
Daniel Parkc64b4c62018-05-09 18:13:39 +0900806 sBuilder.build(),
807 tBuilder.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900808 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900809 ROUTING_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900810 install);
811 }
812
sangho072c4dd2017-05-17 10:45:21 +0900813 private void setOvsNatIngressRule(DeviceId deviceId, IpPrefix cidr, MacAddress dstMac, boolean install) {
814
815 TrafficSelector selector = DefaultTrafficSelector.builder()
816 .matchEthType(Ethernet.TYPE_IPV4)
817 .matchIPDst(cidr)
818 .build();
819
Jian Liedc8b762018-03-22 15:42:00 +0900820 ExtensionTreatment natTreatment = RulePopulatorUtil
821 .niciraConnTrackTreatmentBuilder(driverService, deviceId)
sangho072c4dd2017-05-17 10:45:21 +0900822 .commit(false)
823 .natAction(true)
824 .table((short) 0)
825 .build();
826
827 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
828 .setEthDst(dstMac)
829 .extension(natTreatment, deviceId)
830 .build();
831
832 osFlowRuleService.setRule(
833 appId,
834 deviceId,
835 selector,
836 treatment,
sanghoe765ce22017-06-23 17:54:57 +0900837 PRIORITY_STATEFUL_SNAT_RULE,
sangho072c4dd2017-05-17 10:45:21 +0900838 GW_COMMON_TABLE,
839 install);
840 }
841
842 private void setOvsNatEgressRule(DeviceId deviceId, IpAddress natAddress, long vni, PortNumber output,
843 boolean install) {
844
845 TrafficSelector selector = DefaultTrafficSelector.builder()
846 .matchEthType(Ethernet.TYPE_IPV4)
847 .matchEthDst(DEFAULT_GATEWAY_MAC)
848 .matchTunnelId(vni)
849 .build();
850
Jian Liedc8b762018-03-22 15:42:00 +0900851 ExtensionTreatment natTreatment = RulePopulatorUtil
852 .niciraConnTrackTreatmentBuilder(driverService, deviceId)
sangho072c4dd2017-05-17 10:45:21 +0900853 .commit(true)
854 .natAction(true)
855 .natIp(natAddress)
856 .build();
857
858 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
859 .extension(natTreatment, deviceId)
860 .setEthDst(DEFAULT_EXTERNAL_ROUTER_MAC)
861 .setEthSrc(DEFAULT_GATEWAY_MAC)
862 .setOutput(output)
863 .build();
864
865 osFlowRuleService.setRule(
866 appId,
867 deviceId,
868 selector,
869 treatment,
sanghoe765ce22017-06-23 17:54:57 +0900870 PRIORITY_STATEFUL_SNAT_RULE,
sangho072c4dd2017-05-17 10:45:21 +0900871 GW_COMMON_TABLE,
872 install);
873 }
874
sanghoe765ce22017-06-23 17:54:57 +0900875 private void setRulesToController(DeviceId deviceId, String segmentId, IpPrefix srcSubnet,
876 NetworkType networkType, boolean install) {
877 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
878 .matchEthType(Ethernet.TYPE_IPV4)
Daniel Parkc64b4c62018-05-09 18:13:39 +0900879 .matchIPSrc(srcSubnet)
880 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
881
sanghoe765ce22017-06-23 17:54:57 +0900882 switch (networkType) {
883 case VXLAN:
Daniel Parkc64b4c62018-05-09 18:13:39 +0900884 sBuilder.matchTunnelId(Long.parseLong(segmentId));
sanghoe765ce22017-06-23 17:54:57 +0900885 break;
886 case VLAN:
Daniel Parkc64b4c62018-05-09 18:13:39 +0900887 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
sanghoe765ce22017-06-23 17:54:57 +0900888 break;
889 default:
Jian Li71670d12018-03-02 21:31:07 +0900890 final String error = String.format("%s %s",
891 ERR_UNSUPPORTED_NET_TYPE,
sanghoe765ce22017-06-23 17:54:57 +0900892 networkType.toString());
893 throw new IllegalStateException(error);
894 }
895
Daniel Parkc64b4c62018-05-09 18:13:39 +0900896 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
sanghoe765ce22017-06-23 17:54:57 +0900897
898 if (networkType.equals(NetworkType.VLAN)) {
899 tBuilder.popVlan();
900 }
901
Jian Li4d5c5c32018-04-02 16:38:18 +0900902 tBuilder.punt();
sanghoe765ce22017-06-23 17:54:57 +0900903
904 osFlowRuleService.setRule(
905 appId,
906 deviceId,
907 sBuilder.build(),
908 tBuilder.build(),
909 PRIORITY_EXTERNAL_ROUTING_RULE,
910 GW_COMMON_TABLE,
911 install);
sanghoe765ce22017-06-23 17:54:57 +0900912 }
sangho072c4dd2017-05-17 10:45:21 +0900913
Frank Wang245a6822017-06-14 09:51:35 +0800914 private void setRouterAdminRules(String segmentId, NetworkType networkType, boolean install) {
915 TrafficTreatment treatment;
916 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
917 .matchEthType(Ethernet.TYPE_IPV4);
918
919 switch (networkType) {
920 case VXLAN:
921 sBuilder.matchTunnelId(Long.parseLong(segmentId));
922 break;
923 case VLAN:
924 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
925 break;
926 default:
Jian Li71670d12018-03-02 21:31:07 +0900927 final String error = String.format("%s %s",
928 ERR_UNSUPPORTED_NET_TYPE,
Frank Wang245a6822017-06-14 09:51:35 +0800929 networkType.toString());
930 throw new IllegalStateException(error);
931 }
932
933 treatment = DefaultTrafficTreatment.builder()
934 .drop()
935 .build();
936
937 osNodeService.completeNodes().stream()
938 .filter(osNode -> osNode.type() == COMPUTE)
939 .forEach(osNode -> {
940 osFlowRuleService.setRule(
941 appId,
942 osNode.intgBridge(),
943 sBuilder.build(),
944 treatment,
945 PRIORITY_ADMIN_RULE,
946 ROUTING_TABLE,
947 install);
948 });
949 }
950
Hyunsun Moon44aac662017-02-18 02:07:01 +0900951 private class InternalRouterEventListener implements OpenstackRouterListener {
952
Jian Li34220ea2018-11-14 01:30:24 +0900953 private boolean isRelevantHelper() {
954 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900955 }
956
957 // FIXME only one leader in the cluster should process
958 @Override
959 public void event(OpenstackRouterEvent event) {
960 switch (event.type()) {
961 case OPENSTACK_ROUTER_CREATED:
962 log.debug("Router(name:{}, ID:{}) is created",
963 event.subject().getName(),
964 event.subject().getId());
Jian Li34220ea2018-11-14 01:30:24 +0900965 eventExecutor.execute(() -> {
966
967 if (!isRelevantHelper()) {
968 return;
969 }
970
971 routerUpdated(event.subject());
972 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900973 break;
974 case OPENSTACK_ROUTER_UPDATED:
975 log.debug("Router(name:{}, ID:{}) is updated",
976 event.subject().getName(),
977 event.subject().getId());
Jian Li34220ea2018-11-14 01:30:24 +0900978 eventExecutor.execute(() -> {
979
980 if (!isRelevantHelper()) {
981 return;
982 }
983
984 routerUpdated(event.subject());
985 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900986 break;
987 case OPENSTACK_ROUTER_REMOVED:
988 log.debug("Router(name:{}, ID:{}) is removed",
989 event.subject().getName(),
990 event.subject().getId());
Jian Li34220ea2018-11-14 01:30:24 +0900991 eventExecutor.execute(() -> {
992
993 if (!isRelevantHelper()) {
994 return;
995 }
996
997 routerRemove(event.subject());
998 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900999 break;
1000 case OPENSTACK_ROUTER_INTERFACE_ADDED:
1001 log.debug("Router interface {} added to router {}",
1002 event.routerIface().getPortId(),
1003 event.routerIface().getId());
Jian Li34220ea2018-11-14 01:30:24 +09001004 eventExecutor.execute(() -> {
1005
1006 if (!isRelevantHelper()) {
1007 return;
1008 }
1009
1010 routerIfaceAdded(event.subject(), event.routerIface());
1011 });
Hyunsun Moon44aac662017-02-18 02:07:01 +09001012 break;
1013 case OPENSTACK_ROUTER_INTERFACE_UPDATED:
1014 log.debug("Router interface {} on {} updated",
1015 event.routerIface().getPortId(),
1016 event.routerIface().getId());
1017 break;
1018 case OPENSTACK_ROUTER_INTERFACE_REMOVED:
1019 log.debug("Router interface {} removed from router {}",
1020 event.routerIface().getPortId(),
1021 event.routerIface().getId());
Jian Li34220ea2018-11-14 01:30:24 +09001022 eventExecutor.execute(() -> {
1023
1024 if (!isRelevantHelper()) {
1025 return;
1026 }
1027
1028 routerIfaceRemoved(event.subject(), event.routerIface());
1029 });
Hyunsun Moon44aac662017-02-18 02:07:01 +09001030 break;
1031 case OPENSTACK_ROUTER_GATEWAY_ADDED:
Jian Li32b03622018-11-06 17:54:24 +09001032 log.debug("Router external gateway {} added",
1033 event.externalGateway().getNetworkId());
Ray Milkey08932a72018-02-20 15:34:38 -08001034 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +09001035 case OPENSTACK_ROUTER_GATEWAY_REMOVED:
Jian Li32b03622018-11-06 17:54:24 +09001036 log.debug("Router external gateway {} removed",
1037 event.externalGateway().getNetworkId());
Ray Milkey08932a72018-02-20 15:34:38 -08001038 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +09001039 case OPENSTACK_FLOATING_IP_CREATED:
1040 case OPENSTACK_FLOATING_IP_UPDATED:
1041 case OPENSTACK_FLOATING_IP_REMOVED:
1042 case OPENSTACK_FLOATING_IP_ASSOCIATED:
1043 case OPENSTACK_FLOATING_IP_DISASSOCIATED:
1044 default:
1045 // do nothing for the other events
1046 break;
1047 }
1048 }
1049 }
1050
1051 private class InternalNodeEventListener implements OpenstackNodeListener {
1052
Jian Li34220ea2018-11-14 01:30:24 +09001053 private boolean isRelevantHelper() {
1054 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Hyunsun Moon44aac662017-02-18 02:07:01 +09001055 }
1056
1057 @Override
1058 public void event(OpenstackNodeEvent event) {
1059 OpenstackNode osNode = event.subject();
1060
1061 switch (event.type()) {
Hyunsun Moon0d457362017-06-27 17:19:41 +09001062 case OPENSTACK_NODE_COMPLETE:
1063 case OPENSTACK_NODE_INCOMPLETE:
Daniel Park6ed9cf02018-06-27 19:07:44 +09001064 case OPENSTACK_NODE_UPDATED:
1065 case OPENSTACK_NODE_REMOVED:
Hyunsun Moon44aac662017-02-18 02:07:01 +09001066 eventExecutor.execute(() -> {
Hyunsun Moon0e058f22017-04-19 17:00:52 +09001067 log.info("Reconfigure routers for {}", osNode.hostname());
Jian Li34220ea2018-11-14 01:30:24 +09001068
1069 if (!isRelevantHelper()) {
1070 return;
1071 }
1072
Hyunsun Moon44aac662017-02-18 02:07:01 +09001073 reconfigureRouters();
1074 });
1075 break;
Hyunsun Moon0d457362017-06-27 17:19:41 +09001076 case OPENSTACK_NODE_CREATED:
Hyunsun Moon44aac662017-02-18 02:07:01 +09001077 default:
1078 break;
1079 }
1080 }
1081
1082 private void reconfigureRouters() {
1083 osRouterService.routers().forEach(osRouter -> {
1084 routerUpdated(osRouter);
1085 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
1086 routerIfaceAdded(osRouter, iface);
1087 });
1088 });
1089 }
1090 }
sangho072c4dd2017-05-17 10:45:21 +09001091
1092 private class InternalInstancePortListener implements InstancePortListener {
1093
Jian Li34220ea2018-11-14 01:30:24 +09001094 private boolean isRelevantHelper(InstancePortEvent event) {
1095 return mastershipService.isLocalMaster(event.subject().deviceId());
sangho072c4dd2017-05-17 10:45:21 +09001096 }
1097
1098 @Override
1099 public void event(InstancePortEvent event) {
1100 InstancePort instPort = event.subject();
1101 switch (event.type()) {
sangho072c4dd2017-05-17 10:45:21 +09001102 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Liec5c32b2018-07-13 14:28:58 +09001103 case OPENSTACK_INSTANCE_PORT_UPDATED:
1104 log.info("RoutingHandler: Instance port detected MAC:{} IP:{}",
1105 instPort.macAddress(),
1106 instPort.ipAddress());
1107
Jian Li34220ea2018-11-14 01:30:24 +09001108 eventExecutor.execute(() -> {
1109
1110 if (!isRelevantHelper(event)) {
1111 return;
1112 }
1113
1114 instPortDetected(event.subject());
1115 });
Jian Liec5c32b2018-07-13 14:28:58 +09001116
sangho072c4dd2017-05-17 10:45:21 +09001117 break;
1118 case OPENSTACK_INSTANCE_PORT_VANISHED:
Jian Liec5c32b2018-07-13 14:28:58 +09001119 log.info("RoutingHandler: Instance port vanished MAC:{} IP:{}",
1120 instPort.macAddress(),
1121 instPort.ipAddress());
1122
Jian Li34220ea2018-11-14 01:30:24 +09001123 eventExecutor.execute(() -> {
1124
1125 if (!isRelevantHelper(event)) {
1126 return;
1127 }
1128
1129 instPortRemoved(event.subject());
1130 });
Jian Liec5c32b2018-07-13 14:28:58 +09001131
1132 break;
1133 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
1134 log.info("RoutingHandler: Migration started for MAC:{} IP:{}",
1135 instPort.macAddress(),
1136 instPort.ipAddress());
1137
Jian Li34220ea2018-11-14 01:30:24 +09001138 eventExecutor.execute(() -> {
1139
1140 if (!isRelevantHelper(event)) {
1141 return;
1142 }
1143
1144 instPortDetected(instPort);
1145 });
Jian Liec5c32b2018-07-13 14:28:58 +09001146
sangho072c4dd2017-05-17 10:45:21 +09001147 break;
Jian Li24ec59f2018-05-23 19:01:25 +09001148 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
Jian Liec5c32b2018-07-13 14:28:58 +09001149 log.info("RoutingHandler: Migration finished for MAC:{} IP:{}",
1150 instPort.macAddress(),
1151 instPort.ipAddress());
Jian Li24ec59f2018-05-23 19:01:25 +09001152 eventExecutor.execute(() -> {
Jian Li24ec59f2018-05-23 19:01:25 +09001153 // TODO: need to reconfigure rules to point to update VM
1154 });
Jian Liec5c32b2018-07-13 14:28:58 +09001155
Jian Li24ec59f2018-05-23 19:01:25 +09001156 break;
sangho072c4dd2017-05-17 10:45:21 +09001157 default:
1158 break;
1159 }
1160 }
1161
1162 private void instPortDetected(InstancePort instPort) {
Jian Li32b03622018-11-06 17:54:24 +09001163 if (osNetworkAdminService.network(instPort.networkId()).getNetworkType() == FLAT) {
daniel park796c2eb2018-03-22 17:01:51 +09001164 return;
1165 }
Daniel Parkc64b4c62018-05-09 18:13:39 +09001166
1167 if (useStatefulSnat) {
1168 osNodeService.completeNodes(GATEWAY)
1169 .forEach(gwNode -> setRulesForSnatIngressRule(
1170 gwNode.intgBridge(),
1171 Long.parseLong(osNetworkAdminService
1172 .network(instPort.networkId()).getProviderSegID()),
1173 IpPrefix.valueOf(instPort.ipAddress(), 32),
1174 instPort.deviceId(), true));
1175 }
sangho072c4dd2017-05-17 10:45:21 +09001176 }
1177
1178 private void instPortRemoved(InstancePort instPort) {
Jian Li32b03622018-11-06 17:54:24 +09001179 if (osNetworkAdminService.network(instPort.networkId()).getNetworkType() == FLAT) {
daniel park796c2eb2018-03-22 17:01:51 +09001180 return;
1181 }
Daniel Parkc64b4c62018-05-09 18:13:39 +09001182
1183 if (useStatefulSnat) {
1184 osNodeService.completeNodes(GATEWAY)
1185 .forEach(gwNode -> setRulesForSnatIngressRule(
1186 gwNode.intgBridge(),
1187 Long.parseLong(osNetworkAdminService
1188 .network(instPort.networkId()).getProviderSegID()),
1189 IpPrefix.valueOf(instPort.ipAddress(), 32),
1190 instPort.deviceId(), false));
1191 }
sangho072c4dd2017-05-17 10:45:21 +09001192 }
1193 }
Hyunsun Moon44aac662017-02-18 02:07:01 +09001194}