blob: 28697ed890b3ef2a6939b37de9d11997d4e1c0a0 [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.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
sanghoe765ce22017-06-23 17:54:57 +090024import org.apache.felix.scr.annotations.Modified;
25import org.apache.felix.scr.annotations.Property;
Hyunsun Moon44aac662017-02-18 02:07:01 +090026import org.apache.felix.scr.annotations.Reference;
27import org.apache.felix.scr.annotations.ReferenceCardinality;
28import org.onlab.packet.Ethernet;
29import org.onlab.packet.IPv4;
30import org.onlab.packet.IpAddress;
31import org.onlab.packet.IpPrefix;
sangho072c4dd2017-05-17 10:45:21 +090032import org.onlab.packet.MacAddress;
daniel parkee8700b2017-05-11 15:50:03 +090033import org.onlab.packet.VlanId;
sanghoe765ce22017-06-23 17:54:57 +090034import org.onlab.util.Tools;
35import org.onosproject.cfg.ComponentConfigService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090036import org.onosproject.cluster.ClusterService;
37import org.onosproject.cluster.LeadershipService;
38import org.onosproject.cluster.NodeId;
39import org.onosproject.core.ApplicationId;
40import org.onosproject.core.CoreService;
sangho072c4dd2017-05-17 10:45:21 +090041import org.onosproject.mastership.MastershipService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090042import org.onosproject.net.DeviceId;
43import org.onosproject.net.PortNumber;
sangho072c4dd2017-05-17 10:45:21 +090044import org.onosproject.net.device.DeviceService;
45import org.onosproject.net.driver.DriverService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090046import org.onosproject.net.flow.DefaultTrafficSelector;
47import org.onosproject.net.flow.DefaultTrafficTreatment;
48import org.onosproject.net.flow.TrafficSelector;
49import org.onosproject.net.flow.TrafficTreatment;
sangho072c4dd2017-05-17 10:45:21 +090050import org.onosproject.net.flow.instructions.ExtensionTreatment;
Hyunsun Moon44aac662017-02-18 02:07:01 +090051import org.onosproject.openstacknetworking.api.Constants;
daniel park576969a2018-03-09 07:07:41 +090052import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
sangho072c4dd2017-05-17 10:45:21 +090053import org.onosproject.openstacknetworking.api.InstancePort;
54import org.onosproject.openstacknetworking.api.InstancePortEvent;
55import org.onosproject.openstacknetworking.api.InstancePortListener;
56import org.onosproject.openstacknetworking.api.InstancePortService;
sanghodc375372017-06-08 10:41:30 +090057import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
daniel park32b42202018-03-14 16:53:44 +090058import org.onosproject.openstacknetworking.api.OpenstackNetworkAdminService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090059import org.onosproject.openstacknetworking.api.OpenstackRouterEvent;
60import org.onosproject.openstacknetworking.api.OpenstackRouterListener;
61import org.onosproject.openstacknetworking.api.OpenstackRouterService;
Jian Li26949762018-03-30 15:46:37 +090062import org.onosproject.openstacknetworking.util.RulePopulatorUtil;
Hyunsun Moon0d457362017-06-27 17:19:41 +090063import org.onosproject.openstacknode.api.OpenstackNode;
64import org.onosproject.openstacknode.api.OpenstackNode.NetworkMode;
65import org.onosproject.openstacknode.api.OpenstackNodeEvent;
66import org.onosproject.openstacknode.api.OpenstackNodeListener;
67import org.onosproject.openstacknode.api.OpenstackNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090068import org.openstack4j.model.network.ExternalGateway;
69import org.openstack4j.model.network.Network;
daniel parkee8700b2017-05-11 15:50:03 +090070import org.openstack4j.model.network.NetworkType;
Hyunsun Moon44aac662017-02-18 02:07:01 +090071import org.openstack4j.model.network.Router;
72import org.openstack4j.model.network.RouterInterface;
73import org.openstack4j.model.network.Subnet;
sanghoe765ce22017-06-23 17:54:57 +090074import org.osgi.service.component.ComponentContext;
Hyunsun Moon44aac662017-02-18 02:07:01 +090075import org.slf4j.Logger;
76import org.slf4j.LoggerFactory;
77
sanghoe765ce22017-06-23 17:54:57 +090078import java.util.Dictionary;
Hyunsun Moon44aac662017-02-18 02:07:01 +090079import java.util.Objects;
sangho072c4dd2017-05-17 10:45:21 +090080import java.util.Optional;
Hyunsun Moon44aac662017-02-18 02:07:01 +090081import java.util.Set;
82import java.util.concurrent.ExecutorService;
83import java.util.stream.Collectors;
84
85import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
86import static org.onlab.util.Tools.groupedThreads;
sangho072c4dd2017-05-17 10:45:21 +090087import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_EXTERNAL_ROUTER_MAC;
88import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_GATEWAY_MAC;
sangho072c4dd2017-05-17 10:45:21 +090089import static org.onosproject.openstacknetworking.api.Constants.GW_COMMON_TABLE;
90import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
daniel park796c2eb2018-03-22 17:01:51 +090091import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ADMIN_RULE;
sangho072c4dd2017-05-17 10:45:21 +090092import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_EXTERNAL_ROUTING_RULE;
93import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ICMP_RULE;
94import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_INTERNAL_ROUTING_RULE;
sanghoe765ce22017-06-23 17:54:57 +090095import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_STATEFUL_SNAT_RULE;
sangho072c4dd2017-05-17 10:45:21 +090096import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_SWITCHING_RULE;
97import static org.onosproject.openstacknetworking.api.Constants.ROUTING_TABLE;
Jian Li8abf2fe2018-06-12 18:42:30 +090098import static org.onosproject.openstacknetworking.api.Constants.STAT_OUTBOUND_TABLE;
Jian Lic2403592018-07-18 12:56:45 +090099import static org.onosproject.openstacknetworking.api.InstancePort.State.ACTIVE;
Jian Li26949762018-03-30 15:46:37 +0900100import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900101import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
102import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900103
104/**
105 * Handles OpenStack router events.
106 */
107@Component(immediate = true)
108public class OpenstackRoutingHandler {
109
110 private final Logger log = LoggerFactory.getLogger(getClass());
111
112 private static final String MSG_ENABLED = "Enabled ";
113 private static final String MSG_DISABLED = "Disabled ";
daniel parkee8700b2017-05-11 15:50:03 +0900114 private static final String ERR_UNSUPPORTED_NET_TYPE = "Unsupported network type";
sanghoe765ce22017-06-23 17:54:57 +0900115 private static final boolean USE_STATEFUL_SNAT = false;
116
117 @Property(name = "useStatefulSnat", boolValue = USE_STATEFUL_SNAT,
118 label = "Use Stateful SNAT for source NATing")
119 private boolean useStatefulSnat = USE_STATEFUL_SNAT;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900120
121 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
122 protected CoreService coreService;
123
124 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
125 protected LeadershipService leadershipService;
126
127 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
128 protected ClusterService clusterService;
129
130 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900131 protected OpenstackNodeService osNodeService;
132
133 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
daniel park32b42202018-03-14 16:53:44 +0900134 protected OpenstackNetworkAdminService osNetworkAdminService;
135
136 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900137 protected OpenstackRouterService osRouterService;
138
daniel parkee8700b2017-05-11 15:50:03 +0900139 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho072c4dd2017-05-17 10:45:21 +0900140 protected InstancePortService instancePortService;
141
142 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
143 protected DeviceService deviceService;
144
145 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sanghodc375372017-06-08 10:41:30 +0900146 protected OpenstackFlowRuleService osFlowRuleService;
147
sangho072c4dd2017-05-17 10:45:21 +0900148 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
149 protected MastershipService mastershipService;
150
151 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
152 protected DriverService driverService;
153
sanghoe765ce22017-06-23 17:54:57 +0900154 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
155 protected ComponentConfigService configService;
156
Hyunsun Moon44aac662017-02-18 02:07:01 +0900157 private final ExecutorService eventExecutor = newSingleThreadScheduledExecutor(
158 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
159 private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
160 private final OpenstackRouterListener osRouterListener = new InternalRouterEventListener();
sangho072c4dd2017-05-17 10:45:21 +0900161 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900162
163 private ApplicationId appId;
164 private NodeId localNodeId;
165
166 @Activate
167 protected void activate() {
168 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
169 localNodeId = clusterService.getLocalNode().id();
170 leadershipService.runForLeadership(appId.name());
171 osNodeService.addListener(osNodeListener);
172 osRouterService.addListener(osRouterListener);
sangho072c4dd2017-05-17 10:45:21 +0900173 instancePortService.addListener(instancePortListener);
sanghoe765ce22017-06-23 17:54:57 +0900174 configService.registerProperties(getClass());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900175
176 log.info("Started");
177 }
178
179 @Deactivate
180 protected void deactivate() {
181 osRouterService.removeListener(osRouterListener);
182 osNodeService.removeListener(osNodeListener);
sangho072c4dd2017-05-17 10:45:21 +0900183 instancePortService.removeListener(instancePortListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900184 leadershipService.withdraw(appId.name());
sanghoe765ce22017-06-23 17:54:57 +0900185 configService.unregisterProperties(getClass(), false);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900186 eventExecutor.shutdown();
187
188 log.info("Stopped");
189 }
190
sanghoe765ce22017-06-23 17:54:57 +0900191 @Modified
192 protected void modified(ComponentContext context) {
193 Dictionary<?, ?> properties = context.getProperties();
194 Boolean flag;
195
196 flag = Tools.isPropertyEnabled(properties, "useStatefulSnat");
197 if (flag == null) {
198 log.info("useStatefulSnat is not configured, " +
199 "using current value of {}", useStatefulSnat);
200 } else {
201 useStatefulSnat = flag;
202 log.info("Configured. useStatefulSnat is {}",
203 useStatefulSnat ? "enabled" : "disabled");
204 }
205
206 resetSnatRules();
207 }
208
Hyunsun Moon44aac662017-02-18 02:07:01 +0900209 private void routerUpdated(Router osRouter) {
210 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
Frank Wang245a6822017-06-14 09:51:35 +0800211 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
Jian Liedc8b762018-03-22 15:42:00 +0900212 Network network = osNetworkAdminService.network(osNetworkAdminService.subnet(iface.getSubnetId())
Frank Wang245a6822017-06-14 09:51:35 +0800213 .getNetworkId());
214 setRouterAdminRules(network.getProviderSegID(), network.getNetworkType(), !osRouter.isAdminStateUp());
215 });
216
Jian Liedc8b762018-03-22 15:42:00 +0900217 ExternalPeerRouter externalPeerRouter = osNetworkAdminService.externalPeerRouter(exGateway);
Jian Li5e2ad4a2018-07-16 13:40:53 +0900218 VlanId vlanId = externalPeerRouter == null ? VlanId.NONE : externalPeerRouter.vlanId();
daniel park576969a2018-03-09 07:07:41 +0900219
Hyunsun Moon44aac662017-02-18 02:07:01 +0900220 if (exGateway == null) {
Daniel Park613ac372018-06-28 14:30:11 +0900221 deleteUnassociatedExternalPeerRouter();
daniel park576969a2018-03-09 07:07:41 +0900222 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> setSourceNat(iface, false));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900223 } else {
daniel park32b42202018-03-14 16:53:44 +0900224 osNetworkAdminService.deriveExternalPeerRouterMac(exGateway, osRouter, vlanId);
daniel park576969a2018-03-09 07:07:41 +0900225 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface ->
226 setSourceNat(iface, exGateway.isEnableSnat()));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900227 }
228 }
229
Daniel Park613ac372018-06-28 14:30:11 +0900230 private void deleteUnassociatedExternalPeerRouter() {
231 log.trace("Deleting unassociated external peer router");
232
233 try {
234 Set<String> routerIps = Sets.newConcurrentHashSet();
235
236 osRouterService.routers().stream()
237 .filter(router -> getGatewayIpAddress(router) != null)
238 .map(router -> getGatewayIpAddress(router).toString())
239 .forEach(routerIps::add);
240
241 osNetworkAdminService.externalPeerRouters().stream()
242 .filter(externalPeerRouter ->
Jian Li5e2ad4a2018-07-16 13:40:53 +0900243 !routerIps.contains(externalPeerRouter.ipAddress().toString()))
Daniel Park613ac372018-06-28 14:30:11 +0900244 .forEach(externalPeerRouter -> {
245 osNetworkAdminService
Jian Li5e2ad4a2018-07-16 13:40:53 +0900246 .deleteExternalPeerRouter(externalPeerRouter.ipAddress().toString());
Daniel Park613ac372018-06-28 14:30:11 +0900247 log.trace("Deleted unassociated external peer router {}",
Jian Li5e2ad4a2018-07-16 13:40:53 +0900248 externalPeerRouter.ipAddress().toString());
Daniel Park613ac372018-06-28 14:30:11 +0900249 });
250 } catch (Exception e) {
251 log.error("Exception occurred because of {}", e.toString());
252 }
253 }
254
Frank Wang245a6822017-06-14 09:51:35 +0800255 private void routerRemove(Router osRouter) {
256 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
Jian Liedc8b762018-03-22 15:42:00 +0900257 Network network = osNetworkAdminService.network(osNetworkAdminService.subnet(iface.getSubnetId())
Frank Wang245a6822017-06-14 09:51:35 +0800258 .getNetworkId());
259 setRouterAdminRules(network.getProviderSegID(), network.getNetworkType(), false);
260 });
261 }
262
Hyunsun Moon44aac662017-02-18 02:07:01 +0900263 private void routerIfaceAdded(Router osRouter, RouterInterface osRouterIface) {
Jian Liedc8b762018-03-22 15:42:00 +0900264 Subnet osSubnet = osNetworkAdminService.subnet(osRouterIface.getSubnetId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900265 if (osSubnet == null) {
266 final String error = String.format(
Jian Li71670d12018-03-02 21:31:07 +0900267 "Failed to set flows for router %s: subnet %s does not exist",
Hyunsun Moon44aac662017-02-18 02:07:01 +0900268 osRouterIface.getId(),
269 osRouterIface.getSubnetId());
270 throw new IllegalStateException(error);
271 }
Frank Wang245a6822017-06-14 09:51:35 +0800272
273 if (!osRouter.isAdminStateUp()) {
Jian Liedc8b762018-03-22 15:42:00 +0900274 Network network = osNetworkAdminService.network(osSubnet.getNetworkId());
Frank Wang245a6822017-06-14 09:51:35 +0800275 setRouterAdminRules(network.getProviderSegID(), network.getNetworkType(), true);
276 }
277
Hyunsun Moon44aac662017-02-18 02:07:01 +0900278 setInternalRoutes(osRouter, osSubnet, true);
Daniel Park51f9d1e2018-10-26 13:39:09 +0900279 setGatewayIcmp(osSubnet, osRouter, true);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900280 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
281 if (exGateway != null && exGateway.isEnableSnat()) {
daniel park576969a2018-03-09 07:07:41 +0900282 setSourceNat(osRouterIface, true);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900283 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900284 log.info("Connected subnet({}) to {}", osSubnet.getCidr(), osRouter.getName());
285 }
286
287 private void routerIfaceRemoved(Router osRouter, RouterInterface osRouterIface) {
Jian Liedc8b762018-03-22 15:42:00 +0900288 Subnet osSubnet = osNetworkAdminService.subnet(osRouterIface.getSubnetId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900289 if (osSubnet == null) {
290 final String error = String.format(
Jian Li71670d12018-03-02 21:31:07 +0900291 "Failed to set flows for router %s: subnet %s does not exist",
Hyunsun Moon44aac662017-02-18 02:07:01 +0900292 osRouterIface.getId(),
293 osRouterIface.getSubnetId());
294 throw new IllegalStateException(error);
295 }
296
Frank Wang245a6822017-06-14 09:51:35 +0800297 if (!osRouter.isAdminStateUp()) {
Jian Liedc8b762018-03-22 15:42:00 +0900298 Network network = osNetworkAdminService.network(osSubnet.getNetworkId());
Frank Wang245a6822017-06-14 09:51:35 +0800299 setRouterAdminRules(network.getProviderSegID(), network.getNetworkType(), false);
300 }
301
Hyunsun Moon44aac662017-02-18 02:07:01 +0900302 setInternalRoutes(osRouter, osSubnet, false);
Daniel Park51f9d1e2018-10-26 13:39:09 +0900303 setGatewayIcmp(osSubnet, osRouter, false);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900304 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
305 if (exGateway != null && exGateway.isEnableSnat()) {
daniel park576969a2018-03-09 07:07:41 +0900306 setSourceNat(osRouterIface, false);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900307 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900308 log.info("Disconnected subnet({}) from {}", osSubnet.getCidr(), osRouter.getName());
309 }
310
daniel park576969a2018-03-09 07:07:41 +0900311 private void setSourceNat(RouterInterface routerIface, boolean install) {
Jian Liedc8b762018-03-22 15:42:00 +0900312 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
313 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900314
Hyunsun Moon0d457362017-06-27 17:19:41 +0900315 osNodeService.completeNodes(COMPUTE).forEach(cNode -> {
316 setRulesToGateway(cNode, osNet.getProviderSegID(),
317 IpPrefix.valueOf(osSubnet.getCidr()), osNet.getNetworkType(),
318 install);
319 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900320
sanghoe765ce22017-06-23 17:54:57 +0900321 if (useStatefulSnat) {
322 setStatefulSnatRules(routerIface, install);
323 } else {
324 setReactiveSnatRules(routerIface, install);
325 }
326
327 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
328 log.info(updateStr + "external access for subnet({})", osSubnet.getCidr());
329 }
330
331 private void setStatefulSnatRules(RouterInterface routerIface, boolean install) {
Jian Liedc8b762018-03-22 15:42:00 +0900332 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
333 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
sanghoe765ce22017-06-23 17:54:57 +0900334
daniel park796c2eb2018-03-22 17:01:51 +0900335 if (osNet.getNetworkType() == NetworkType.FLAT) {
336 return;
337 }
338
sanghoe765ce22017-06-23 17:54:57 +0900339 Optional<Router> osRouter = osRouterService.routers().stream()
340 .filter(router -> osRouterService.routerInterfaces(routerIface.getId()) != null)
341 .findAny();
342
343 if (!osRouter.isPresent()) {
344 log.error("Cannot find a router for router interface {} ", routerIface);
345 return;
346 }
347 IpAddress natAddress = getGatewayIpAddress(osRouter.get());
sangho072c4dd2017-05-17 10:45:21 +0900348 if (natAddress == null) {
349 return;
350 }
Jian Liedc8b762018-03-22 15:42:00 +0900351 String netId = osNetworkAdminService.subnet(routerIface.getSubnetId()).getNetworkId();
sangho072c4dd2017-05-17 10:45:21 +0900352
353 osNodeService.completeNodes(OpenstackNode.NodeType.GATEWAY)
354 .forEach(gwNode -> {
daniel park576969a2018-03-09 07:07:41 +0900355 instancePortService.instancePorts(netId)
Jian Lic2403592018-07-18 12:56:45 +0900356 .stream()
357 .filter(port -> port.state() == ACTIVE)
daniel park576969a2018-03-09 07:07:41 +0900358 .forEach(port -> setRulesForSnatIngressRule(gwNode.intgBridge(),
sangho072c4dd2017-05-17 10:45:21 +0900359 Long.parseLong(osNet.getProviderSegID()),
360 IpPrefix.valueOf(port.ipAddress(), 32),
361 port.deviceId(),
362 install));
363
364 setOvsNatIngressRule(gwNode.intgBridge(),
365 IpPrefix.valueOf(natAddress, 32),
366 Constants.DEFAULT_EXTERNAL_ROUTER_MAC, install);
367 setOvsNatEgressRule(gwNode.intgBridge(),
368 natAddress, Long.parseLong(osNet.getProviderSegID()),
369 gwNode.patchPortNum(), install);
370 });
sanghoe765ce22017-06-23 17:54:57 +0900371 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900372
sanghoe765ce22017-06-23 17:54:57 +0900373 private void setReactiveSnatRules(RouterInterface routerIface, boolean install) {
Jian Liedc8b762018-03-22 15:42:00 +0900374 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
375 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
sanghoe765ce22017-06-23 17:54:57 +0900376
377 osNodeService.completeNodes(GATEWAY)
378 .forEach(gwNode -> setRulesToController(
379 gwNode.intgBridge(),
380 osNet.getProviderSegID(),
381 IpPrefix.valueOf(osSubnet.getCidr()),
382 osNet.getNetworkType(),
383 install));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900384 }
385
sangho072c4dd2017-05-17 10:45:21 +0900386 private IpAddress getGatewayIpAddress(Router osRouter) {
387
Daniel Park613ac372018-06-28 14:30:11 +0900388 if (osRouter.getExternalGatewayInfo() == null) {
389 return null;
390 }
Jian Liedc8b762018-03-22 15:42:00 +0900391 String extNetId = osNetworkAdminService.network(osRouter.getExternalGatewayInfo().getNetworkId()).getId();
392 Optional<Subnet> extSubnet = osNetworkAdminService.subnets().stream()
sangho072c4dd2017-05-17 10:45:21 +0900393 .filter(subnet -> subnet.getNetworkId().equals(extNetId))
394 .findAny();
395
396 if (!extSubnet.isPresent()) {
397 log.error("Cannot find externel subnet for the router");
398 return null;
399 }
400
401 return IpAddress.valueOf(extSubnet.get().getGateway());
402 }
403
sanghoe765ce22017-06-23 17:54:57 +0900404 private void resetSnatRules() {
405 if (useStatefulSnat) {
406 osRouterService.routerInterfaces().forEach(
407 routerIface -> {
408 setReactiveSnatRules(routerIface, false);
409 setStatefulSnatRules(routerIface, true);
410 }
411 );
412 } else {
413 osRouterService.routerInterfaces().forEach(
414 routerIface -> {
415 setStatefulSnatRules(routerIface, false);
416 setReactiveSnatRules(routerIface, true);
417 }
418 );
419 }
420 }
421
Daniel Park51f9d1e2018-10-26 13:39:09 +0900422 private void setGatewayIcmp(Subnet osSubnet, Router osRouter, boolean install) {
daniel parkb5817102018-02-15 00:18:51 +0900423 OpenstackNode sourceNatGateway = osNodeService.completeNodes(GATEWAY).stream().findFirst().orElse(null);
424
425 if (sourceNatGateway == null) {
426 return;
427 }
428
Hyunsun Moon44aac662017-02-18 02:07:01 +0900429 if (Strings.isNullOrEmpty(osSubnet.getGateway())) {
430 // do nothing if no gateway is set
431 return;
432 }
433
434 // take ICMP request to a subnet gateway through gateway node group
Jian Liedc8b762018-03-22 15:42:00 +0900435 Network network = osNetworkAdminService.network(osSubnet.getNetworkId());
Daniel Park51f9d1e2018-10-26 13:39:09 +0900436 Set<Subnet> routableSubnets = routableSubnets(osRouter, osSubnet.getId());
437
daniel parkee8700b2017-05-11 15:50:03 +0900438 switch (network.getNetworkType()) {
439 case VXLAN:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900440 osNodeService.completeNodes(COMPUTE).stream()
441 .filter(cNode -> cNode.dataIp() != null)
Daniel Park51f9d1e2018-10-26 13:39:09 +0900442 .forEach(cNode -> setRulesToGatewayWithRoutableSubnets(
Hyunsun Moon0d457362017-06-27 17:19:41 +0900443 cNode,
daniel parkb5817102018-02-15 00:18:51 +0900444 sourceNatGateway,
daniel parkee8700b2017-05-11 15:50:03 +0900445 network.getProviderSegID(),
Daniel Park51f9d1e2018-10-26 13:39:09 +0900446 osSubnet,
447 routableSubnets,
daniel parkee8700b2017-05-11 15:50:03 +0900448 NetworkMode.VXLAN,
449 install));
450 break;
451 case VLAN:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900452 osNodeService.completeNodes(COMPUTE).stream()
453 .filter(cNode -> cNode.vlanPortNum() != null)
Daniel Park51f9d1e2018-10-26 13:39:09 +0900454 .forEach(cNode -> setRulesToGatewayWithRoutableSubnets(
Hyunsun Moon0d457362017-06-27 17:19:41 +0900455 cNode,
daniel parkb5817102018-02-15 00:18:51 +0900456 sourceNatGateway,
daniel parkee8700b2017-05-11 15:50:03 +0900457 network.getProviderSegID(),
Daniel Park51f9d1e2018-10-26 13:39:09 +0900458 osSubnet,
459 routableSubnets,
daniel parkee8700b2017-05-11 15:50:03 +0900460 NetworkMode.VLAN,
461 install));
462 break;
463 default:
Jian Li71670d12018-03-02 21:31:07 +0900464 final String error = String.format("%s %s",
465 ERR_UNSUPPORTED_NET_TYPE,
daniel parkee8700b2017-05-11 15:50:03 +0900466 network.getNetworkType().toString());
467 throw new IllegalStateException(error);
468 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900469
470 IpAddress gatewayIp = IpAddress.valueOf(osSubnet.getGateway());
daniel park576969a2018-03-09 07:07:41 +0900471 osNodeService.completeNodes(GATEWAY).forEach(gNode ->
Hyunsun Moon0d457362017-06-27 17:19:41 +0900472 setGatewayIcmpRule(
473 gatewayIp,
474 gNode.intgBridge(),
daniel park576969a2018-03-09 07:07:41 +0900475 install));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900476
477 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
478 log.debug(updateStr + "ICMP to {}", osSubnet.getGateway());
479 }
480
481 private void setInternalRoutes(Router osRouter, Subnet updatedSubnet, boolean install) {
Jian Liedc8b762018-03-22 15:42:00 +0900482 Network updatedNetwork = osNetworkAdminService.network(updatedSubnet.getNetworkId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900483 Set<Subnet> routableSubnets = routableSubnets(osRouter, updatedSubnet.getId());
Jian Lib6969502018-10-30 20:38:07 +0900484 String updatedSegmentId = getSegmentId(updatedSubnet);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900485
486 // installs rule from/to my subnet intentionally to fix ICMP failure
487 // to my subnet gateway if no external gateway added to the router
Hyunsun Moon0d457362017-06-27 17:19:41 +0900488 osNodeService.completeNodes(COMPUTE).forEach(cNode -> {
489 setInternalRouterRules(
490 cNode.intgBridge(),
Jian Lib6969502018-10-30 20:38:07 +0900491 updatedSegmentId,
492 updatedSegmentId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900493 IpPrefix.valueOf(updatedSubnet.getCidr()),
494 IpPrefix.valueOf(updatedSubnet.getCidr()),
495 updatedNetwork.getNetworkType(),
496 install
497 );
Hyunsun Moon44aac662017-02-18 02:07:01 +0900498
Hyunsun Moon0d457362017-06-27 17:19:41 +0900499 routableSubnets.forEach(subnet -> {
500 setInternalRouterRules(
501 cNode.intgBridge(),
Jian Lib6969502018-10-30 20:38:07 +0900502 updatedSegmentId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900503 getSegmentId(subnet),
504 IpPrefix.valueOf(updatedSubnet.getCidr()),
505 IpPrefix.valueOf(subnet.getCidr()),
506 updatedNetwork.getNetworkType(),
507 install
508 );
509 setInternalRouterRules(
510 cNode.intgBridge(),
511 getSegmentId(subnet),
Jian Lib6969502018-10-30 20:38:07 +0900512 updatedSegmentId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900513 IpPrefix.valueOf(subnet.getCidr()),
514 IpPrefix.valueOf(updatedSubnet.getCidr()),
515 updatedNetwork.getNetworkType(),
516 install
517 );
518 });
519 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900520
daniel parkee8700b2017-05-11 15:50:03 +0900521
Hyunsun Moon44aac662017-02-18 02:07:01 +0900522 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
523 routableSubnets.forEach(subnet -> log.debug(
524 updateStr + "route between subnet:{} and subnet:{}",
525 subnet.getCidr(),
526 updatedSubnet.getCidr()));
527 }
528
529 private Set<Subnet> routableSubnets(Router osRouter, String osSubnetId) {
530 Set<Subnet> osSubnets = osRouterService.routerInterfaces(osRouter.getId())
531 .stream()
532 .filter(iface -> !Objects.equals(iface.getSubnetId(), osSubnetId))
Jian Liedc8b762018-03-22 15:42:00 +0900533 .map(iface -> osNetworkAdminService.subnet(iface.getSubnetId()))
Hyunsun Moon44aac662017-02-18 02:07:01 +0900534 .collect(Collectors.toSet());
535 return ImmutableSet.copyOf(osSubnets);
536 }
537
daniel parkee8700b2017-05-11 15:50:03 +0900538 private String getSegmentId(Subnet osSubnet) {
Jian Liedc8b762018-03-22 15:42:00 +0900539 return osNetworkAdminService.network(osSubnet.getNetworkId()).getProviderSegID();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900540 }
541
542 private void setGatewayIcmpRule(IpAddress gatewayIp, DeviceId deviceId, boolean install) {
543 TrafficSelector selector = DefaultTrafficSelector.builder()
544 .matchEthType(Ethernet.TYPE_IPV4)
545 .matchIPProtocol(IPv4.PROTOCOL_ICMP)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900546 .matchIPDst(gatewayIp.getIp4Address().toIpPrefix())
Hyunsun Moon44aac662017-02-18 02:07:01 +0900547 .build();
548
549 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Li4d5c5c32018-04-02 16:38:18 +0900550 .punt()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900551 .build();
552
sanghodc375372017-06-08 10:41:30 +0900553 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900554 appId,
555 deviceId,
556 selector,
557 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900558 PRIORITY_ICMP_RULE,
sanghodc375372017-06-08 10:41:30 +0900559 Constants.GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900560 install);
561 }
562
daniel parkee8700b2017-05-11 15:50:03 +0900563 private void setInternalRouterRules(DeviceId deviceId, String srcSegmentId, String dstSegmentId,
564 IpPrefix srcSubnet, IpPrefix dstSubnet,
565 NetworkType networkType, boolean install) {
566 TrafficSelector selector;
567 TrafficTreatment treatment;
568 switch (networkType) {
569 case VXLAN:
570 selector = DefaultTrafficSelector.builder()
571 .matchEthType(Ethernet.TYPE_IPV4)
572 .matchTunnelId(Long.parseLong(srcSegmentId))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900573 .matchIPSrc(srcSubnet.getIp4Prefix())
574 .matchIPDst(dstSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900575 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900576
daniel parkee8700b2017-05-11 15:50:03 +0900577 treatment = DefaultTrafficTreatment.builder()
578 .setTunnelId(Long.parseLong(dstSegmentId))
Jian Li8abf2fe2018-06-12 18:42:30 +0900579 .transition(STAT_OUTBOUND_TABLE)
daniel parkee8700b2017-05-11 15:50:03 +0900580 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900581
sanghodc375372017-06-08 10:41:30 +0900582 osFlowRuleService.setRule(
daniel parkee8700b2017-05-11 15:50:03 +0900583 appId,
584 deviceId,
585 selector,
586 treatment,
daniel parkee8700b2017-05-11 15:50:03 +0900587 PRIORITY_INTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900588 ROUTING_TABLE,
daniel parkee8700b2017-05-11 15:50:03 +0900589 install);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900590
daniel parkee8700b2017-05-11 15:50:03 +0900591 selector = DefaultTrafficSelector.builder()
592 .matchEthType(Ethernet.TYPE_IPV4)
593 .matchTunnelId(Long.parseLong(dstSegmentId))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900594 .matchIPSrc(srcSubnet.getIp4Prefix())
595 .matchIPDst(dstSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900596 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900597
daniel parkee8700b2017-05-11 15:50:03 +0900598 treatment = DefaultTrafficTreatment.builder()
599 .setTunnelId(Long.parseLong(dstSegmentId))
Jian Li8abf2fe2018-06-12 18:42:30 +0900600 .transition(STAT_OUTBOUND_TABLE)
daniel parkee8700b2017-05-11 15:50:03 +0900601 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900602
sanghodc375372017-06-08 10:41:30 +0900603 osFlowRuleService.setRule(
daniel parkee8700b2017-05-11 15:50:03 +0900604 appId,
605 deviceId,
606 selector,
607 treatment,
daniel parkee8700b2017-05-11 15:50:03 +0900608 PRIORITY_INTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900609 ROUTING_TABLE,
daniel parkee8700b2017-05-11 15:50:03 +0900610 install);
611 break;
612 case VLAN:
613 selector = DefaultTrafficSelector.builder()
614 .matchEthType(Ethernet.TYPE_IPV4)
615 .matchVlanId(VlanId.vlanId(srcSegmentId))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900616 .matchIPSrc(srcSubnet.getIp4Prefix())
617 .matchIPDst(dstSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900618 .build();
619
620 treatment = DefaultTrafficTreatment.builder()
621 .setVlanId(VlanId.vlanId(dstSegmentId))
Jian Li8abf2fe2018-06-12 18:42:30 +0900622 .transition(STAT_OUTBOUND_TABLE)
daniel parkee8700b2017-05-11 15:50:03 +0900623 .build();
624
sanghodc375372017-06-08 10:41:30 +0900625 osFlowRuleService.setRule(
daniel parkee8700b2017-05-11 15:50:03 +0900626 appId,
627 deviceId,
628 selector,
629 treatment,
daniel parkee8700b2017-05-11 15:50:03 +0900630 PRIORITY_INTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900631 ROUTING_TABLE,
daniel parkee8700b2017-05-11 15:50:03 +0900632 install);
633
634 selector = DefaultTrafficSelector.builder()
635 .matchEthType(Ethernet.TYPE_IPV4)
636 .matchVlanId(VlanId.vlanId(dstSegmentId))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900637 .matchIPSrc(srcSubnet.getIp4Prefix())
638 .matchIPDst(dstSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900639 .build();
640
641 treatment = DefaultTrafficTreatment.builder()
642 .setVlanId(VlanId.vlanId(dstSegmentId))
Jian Li8abf2fe2018-06-12 18:42:30 +0900643 .transition(STAT_OUTBOUND_TABLE)
daniel parkee8700b2017-05-11 15:50:03 +0900644 .build();
645
sanghodc375372017-06-08 10:41:30 +0900646 osFlowRuleService.setRule(
daniel parkee8700b2017-05-11 15:50:03 +0900647 appId,
648 deviceId,
649 selector,
650 treatment,
daniel parkee8700b2017-05-11 15:50:03 +0900651 PRIORITY_INTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900652 ROUTING_TABLE,
daniel parkee8700b2017-05-11 15:50:03 +0900653 install);
654 break;
655 default:
Jian Li71670d12018-03-02 21:31:07 +0900656 final String error = String.format("%s %s",
657 ERR_UNSUPPORTED_NET_TYPE,
daniel parkee8700b2017-05-11 15:50:03 +0900658 networkType.toString());
659 throw new IllegalStateException(error);
660 }
661
Hyunsun Moon44aac662017-02-18 02:07:01 +0900662 }
663
Hyunsun Moon0d457362017-06-27 17:19:41 +0900664 private void setRulesToGateway(OpenstackNode osNode, String segmentId, IpPrefix srcSubnet,
daniel parkee8700b2017-05-11 15:50:03 +0900665 NetworkType networkType, boolean install) {
daniel parkb5817102018-02-15 00:18:51 +0900666 OpenstackNode sourceNatGateway = osNodeService.completeNodes(GATEWAY).stream().findFirst().orElse(null);
667
668 if (sourceNatGateway == null) {
669 return;
670 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900671
daniel parkee8700b2017-05-11 15:50:03 +0900672 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
673 .matchEthType(Ethernet.TYPE_IPV4)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900674 .matchIPSrc(srcSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900675 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
676
677 switch (networkType) {
678 case VXLAN:
679 sBuilder.matchTunnelId(Long.parseLong(segmentId));
daniel parkee8700b2017-05-11 15:50:03 +0900680 break;
681 case VLAN:
682 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
daniel parkee8700b2017-05-11 15:50:03 +0900683 break;
684 default:
Jian Li71670d12018-03-02 21:31:07 +0900685 final String error = String.format("%s %s",
686 ERR_UNSUPPORTED_NET_TYPE,
daniel parkee8700b2017-05-11 15:50:03 +0900687 networkType.toString());
688 throw new IllegalStateException(error);
689 }
690
Daniel Parkc64b4c62018-05-09 18:13:39 +0900691 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
692
693 switch (networkType) {
694 case VXLAN:
695 tBuilder.extension(buildExtension(
696 deviceService,
697 osNode.intgBridge(),
698 sourceNatGateway.dataIp().getIp4Address()),
699 osNode.intgBridge())
700 .setOutput(osNode.tunnelPortNum());
701 break;
702
703 case VLAN:
704 tBuilder.setOutput(osNode.vlanPortNum());
705 break;
706
707 default:
708 break;
709 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900710
sanghodc375372017-06-08 10:41:30 +0900711 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900712 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900713 osNode.intgBridge(),
daniel parkee8700b2017-05-11 15:50:03 +0900714 sBuilder.build(),
Daniel Parkc64b4c62018-05-09 18:13:39 +0900715 tBuilder.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900716 PRIORITY_EXTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900717 ROUTING_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900718 install);
719 }
720
sangho072c4dd2017-05-17 10:45:21 +0900721 private void setRulesForSnatIngressRule(DeviceId deviceId, Long vni, IpPrefix destVmIp,
722 DeviceId dstDeviceId, boolean install) {
723
724 TrafficSelector selector = DefaultTrafficSelector.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900725 .matchEthType(Ethernet.TYPE_IPV4)
sangho072c4dd2017-05-17 10:45:21 +0900726 .matchIPDst(destVmIp)
727 .build();
Hyunsun Moon0d457362017-06-27 17:19:41 +0900728
sangho072c4dd2017-05-17 10:45:21 +0900729 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
730 .setTunnelId(vni)
731 .extension(buildExtension(
732 deviceService,
733 deviceId,
734 osNodeService.node(dstDeviceId).dataIp().getIp4Address()),
735 deviceId)
736 .setOutput(osNodeService.node(deviceId).tunnelPortNum())
737 .build();
daniel parkee8700b2017-05-11 15:50:03 +0900738
sanghodc375372017-06-08 10:41:30 +0900739 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900740 appId,
sangho072c4dd2017-05-17 10:45:21 +0900741 deviceId,
742 selector,
743 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900744 PRIORITY_EXTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900745 Constants.GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900746 install);
747 }
748
Daniel Park51f9d1e2018-10-26 13:39:09 +0900749 private void setRulesToGatewayWithRoutableSubnets(OpenstackNode osNode, OpenstackNode sourceNatGateway,
750 String segmentId, Subnet updatedSubnet,
751 Set<Subnet> routableSubnets, NetworkMode networkMode,
752 boolean install) {
753 //At first we install flow rules to gateway with segId and gatewayIp of updated subnet
754 setRulesToGatewayWithDstIp(osNode, sourceNatGateway, segmentId, IpAddress.valueOf(updatedSubnet.getGateway()),
755 networkMode, install);
756
757 routableSubnets.forEach(subnet -> {
758 setRulesToGatewayWithDstIp(osNode, sourceNatGateway,
759 segmentId, IpAddress.valueOf(subnet.getGateway()),
760 networkMode, install);
761
762 Network network = osNetworkAdminService.network(subnet.getNetworkId());
763 setRulesToGatewayWithDstIp(osNode, sourceNatGateway,
764 network.getProviderSegID(), IpAddress.valueOf(updatedSubnet.getGateway()),
765 networkMode, install);
766 });
767 }
768
daniel parkb5817102018-02-15 00:18:51 +0900769 private void setRulesToGatewayWithDstIp(OpenstackNode osNode, OpenstackNode sourceNatGateway,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900770 String segmentId, IpAddress dstIp,
771 NetworkMode networkMode, boolean install) {
Daniel Parkc64b4c62018-05-09 18:13:39 +0900772 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
773 .matchEthType(Ethernet.TYPE_IPV4)
774 .matchIPDst(dstIp.getIp4Address().toIpPrefix());
775
Daniel Parkc64b4c62018-05-09 18:13:39 +0900776 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
777
778 switch (networkMode) {
779 case VXLAN:
Daniel Park51f9d1e2018-10-26 13:39:09 +0900780 sBuilder.matchTunnelId(Long.parseLong(segmentId));
Daniel Parkc64b4c62018-05-09 18:13:39 +0900781 tBuilder.extension(buildExtension(
daniel parkb5817102018-02-15 00:18:51 +0900782 deviceService,
783 osNode.intgBridge(),
784 sourceNatGateway.dataIp().getIp4Address()),
785 osNode.intgBridge())
Daniel Parkc64b4c62018-05-09 18:13:39 +0900786 .setOutput(osNode.tunnelPortNum());
787 break;
788
789 case VLAN:
Daniel Park51f9d1e2018-10-26 13:39:09 +0900790 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
Daniel Parkc64b4c62018-05-09 18:13:39 +0900791 tBuilder.setOutput(osNode.vlanPortNum());
792 break;
793
794 default:
795 break;
796 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900797
sanghodc375372017-06-08 10:41:30 +0900798 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900799 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900800 osNode.intgBridge(),
Daniel Parkc64b4c62018-05-09 18:13:39 +0900801 sBuilder.build(),
802 tBuilder.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900803 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900804 ROUTING_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900805 install);
806 }
807
sangho072c4dd2017-05-17 10:45:21 +0900808 private void setOvsNatIngressRule(DeviceId deviceId, IpPrefix cidr, MacAddress dstMac, boolean install) {
809
810 TrafficSelector selector = DefaultTrafficSelector.builder()
811 .matchEthType(Ethernet.TYPE_IPV4)
812 .matchIPDst(cidr)
813 .build();
814
Jian Liedc8b762018-03-22 15:42:00 +0900815 ExtensionTreatment natTreatment = RulePopulatorUtil
816 .niciraConnTrackTreatmentBuilder(driverService, deviceId)
sangho072c4dd2017-05-17 10:45:21 +0900817 .commit(false)
818 .natAction(true)
819 .table((short) 0)
820 .build();
821
822 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
823 .setEthDst(dstMac)
824 .extension(natTreatment, deviceId)
825 .build();
826
827 osFlowRuleService.setRule(
828 appId,
829 deviceId,
830 selector,
831 treatment,
sanghoe765ce22017-06-23 17:54:57 +0900832 PRIORITY_STATEFUL_SNAT_RULE,
sangho072c4dd2017-05-17 10:45:21 +0900833 GW_COMMON_TABLE,
834 install);
835 }
836
837 private void setOvsNatEgressRule(DeviceId deviceId, IpAddress natAddress, long vni, PortNumber output,
838 boolean install) {
839
840 TrafficSelector selector = DefaultTrafficSelector.builder()
841 .matchEthType(Ethernet.TYPE_IPV4)
842 .matchEthDst(DEFAULT_GATEWAY_MAC)
843 .matchTunnelId(vni)
844 .build();
845
Jian Liedc8b762018-03-22 15:42:00 +0900846 ExtensionTreatment natTreatment = RulePopulatorUtil
847 .niciraConnTrackTreatmentBuilder(driverService, deviceId)
sangho072c4dd2017-05-17 10:45:21 +0900848 .commit(true)
849 .natAction(true)
850 .natIp(natAddress)
851 .build();
852
853 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
854 .extension(natTreatment, deviceId)
855 .setEthDst(DEFAULT_EXTERNAL_ROUTER_MAC)
856 .setEthSrc(DEFAULT_GATEWAY_MAC)
857 .setOutput(output)
858 .build();
859
860 osFlowRuleService.setRule(
861 appId,
862 deviceId,
863 selector,
864 treatment,
sanghoe765ce22017-06-23 17:54:57 +0900865 PRIORITY_STATEFUL_SNAT_RULE,
sangho072c4dd2017-05-17 10:45:21 +0900866 GW_COMMON_TABLE,
867 install);
868 }
869
sanghoe765ce22017-06-23 17:54:57 +0900870 private void setRulesToController(DeviceId deviceId, String segmentId, IpPrefix srcSubnet,
871 NetworkType networkType, boolean install) {
872 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
873 .matchEthType(Ethernet.TYPE_IPV4)
Daniel Parkc64b4c62018-05-09 18:13:39 +0900874 .matchIPSrc(srcSubnet)
875 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
876
sanghoe765ce22017-06-23 17:54:57 +0900877 switch (networkType) {
878 case VXLAN:
Daniel Parkc64b4c62018-05-09 18:13:39 +0900879 sBuilder.matchTunnelId(Long.parseLong(segmentId));
sanghoe765ce22017-06-23 17:54:57 +0900880 break;
881 case VLAN:
Daniel Parkc64b4c62018-05-09 18:13:39 +0900882 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
sanghoe765ce22017-06-23 17:54:57 +0900883 break;
884 default:
Jian Li71670d12018-03-02 21:31:07 +0900885 final String error = String.format("%s %s",
886 ERR_UNSUPPORTED_NET_TYPE,
sanghoe765ce22017-06-23 17:54:57 +0900887 networkType.toString());
888 throw new IllegalStateException(error);
889 }
890
Daniel Parkc64b4c62018-05-09 18:13:39 +0900891 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
sanghoe765ce22017-06-23 17:54:57 +0900892
893 if (networkType.equals(NetworkType.VLAN)) {
894 tBuilder.popVlan();
895 }
896
Jian Li4d5c5c32018-04-02 16:38:18 +0900897 tBuilder.punt();
sanghoe765ce22017-06-23 17:54:57 +0900898
899 osFlowRuleService.setRule(
900 appId,
901 deviceId,
902 sBuilder.build(),
903 tBuilder.build(),
904 PRIORITY_EXTERNAL_ROUTING_RULE,
905 GW_COMMON_TABLE,
906 install);
sanghoe765ce22017-06-23 17:54:57 +0900907 }
sangho072c4dd2017-05-17 10:45:21 +0900908
Frank Wang245a6822017-06-14 09:51:35 +0800909 private void setRouterAdminRules(String segmentId, NetworkType networkType, boolean install) {
910 TrafficTreatment treatment;
911 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
912 .matchEthType(Ethernet.TYPE_IPV4);
913
914 switch (networkType) {
915 case VXLAN:
916 sBuilder.matchTunnelId(Long.parseLong(segmentId));
917 break;
918 case VLAN:
919 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
920 break;
921 default:
Jian Li71670d12018-03-02 21:31:07 +0900922 final String error = String.format("%s %s",
923 ERR_UNSUPPORTED_NET_TYPE,
Frank Wang245a6822017-06-14 09:51:35 +0800924 networkType.toString());
925 throw new IllegalStateException(error);
926 }
927
928 treatment = DefaultTrafficTreatment.builder()
929 .drop()
930 .build();
931
932 osNodeService.completeNodes().stream()
933 .filter(osNode -> osNode.type() == COMPUTE)
934 .forEach(osNode -> {
935 osFlowRuleService.setRule(
936 appId,
937 osNode.intgBridge(),
938 sBuilder.build(),
939 treatment,
940 PRIORITY_ADMIN_RULE,
941 ROUTING_TABLE,
942 install);
943 });
944 }
945
Hyunsun Moon44aac662017-02-18 02:07:01 +0900946 private class InternalRouterEventListener implements OpenstackRouterListener {
947
948 @Override
949 public boolean isRelevant(OpenstackRouterEvent event) {
950 // do not allow to proceed without leadership
951 NodeId leader = leadershipService.getLeader(appId.name());
952 return Objects.equals(localNodeId, leader);
953 }
954
955 // FIXME only one leader in the cluster should process
956 @Override
957 public void event(OpenstackRouterEvent event) {
958 switch (event.type()) {
959 case OPENSTACK_ROUTER_CREATED:
960 log.debug("Router(name:{}, ID:{}) is created",
961 event.subject().getName(),
962 event.subject().getId());
963 eventExecutor.execute(() -> routerUpdated(event.subject()));
964 break;
965 case OPENSTACK_ROUTER_UPDATED:
966 log.debug("Router(name:{}, ID:{}) is updated",
967 event.subject().getName(),
968 event.subject().getId());
969 eventExecutor.execute(() -> routerUpdated(event.subject()));
970 break;
971 case OPENSTACK_ROUTER_REMOVED:
972 log.debug("Router(name:{}, ID:{}) is removed",
973 event.subject().getName(),
974 event.subject().getId());
Frank Wang245a6822017-06-14 09:51:35 +0800975 eventExecutor.execute(() -> routerRemove(event.subject()));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900976 break;
977 case OPENSTACK_ROUTER_INTERFACE_ADDED:
978 log.debug("Router interface {} added to router {}",
979 event.routerIface().getPortId(),
980 event.routerIface().getId());
981 eventExecutor.execute(() -> routerIfaceAdded(
982 event.subject(),
983 event.routerIface()));
984 break;
985 case OPENSTACK_ROUTER_INTERFACE_UPDATED:
986 log.debug("Router interface {} on {} updated",
987 event.routerIface().getPortId(),
988 event.routerIface().getId());
989 break;
990 case OPENSTACK_ROUTER_INTERFACE_REMOVED:
991 log.debug("Router interface {} removed from router {}",
992 event.routerIface().getPortId(),
993 event.routerIface().getId());
994 eventExecutor.execute(() -> routerIfaceRemoved(
995 event.subject(),
996 event.routerIface()));
997 break;
998 case OPENSTACK_ROUTER_GATEWAY_ADDED:
daniel parkb5817102018-02-15 00:18:51 +0900999 log.debug("Router external gateway {} added", event.externalGateway().getNetworkId());
Ray Milkey08932a72018-02-20 15:34:38 -08001000 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +09001001 case OPENSTACK_ROUTER_GATEWAY_REMOVED:
daniel parkb5817102018-02-15 00:18:51 +09001002 log.debug("Router external gateway {} removed", event.externalGateway().getNetworkId());
Ray Milkey08932a72018-02-20 15:34:38 -08001003 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +09001004 case OPENSTACK_FLOATING_IP_CREATED:
1005 case OPENSTACK_FLOATING_IP_UPDATED:
1006 case OPENSTACK_FLOATING_IP_REMOVED:
1007 case OPENSTACK_FLOATING_IP_ASSOCIATED:
1008 case OPENSTACK_FLOATING_IP_DISASSOCIATED:
1009 default:
1010 // do nothing for the other events
1011 break;
1012 }
1013 }
1014 }
1015
1016 private class InternalNodeEventListener implements OpenstackNodeListener {
1017
1018 @Override
1019 public boolean isRelevant(OpenstackNodeEvent event) {
1020 // do not allow to proceed without leadership
1021 NodeId leader = leadershipService.getLeader(appId.name());
1022 return Objects.equals(localNodeId, leader);
1023 }
1024
1025 @Override
1026 public void event(OpenstackNodeEvent event) {
1027 OpenstackNode osNode = event.subject();
1028
1029 switch (event.type()) {
Hyunsun Moon0d457362017-06-27 17:19:41 +09001030 case OPENSTACK_NODE_COMPLETE:
1031 case OPENSTACK_NODE_INCOMPLETE:
Daniel Park6ed9cf02018-06-27 19:07:44 +09001032 case OPENSTACK_NODE_UPDATED:
1033 case OPENSTACK_NODE_REMOVED:
Hyunsun Moon44aac662017-02-18 02:07:01 +09001034 eventExecutor.execute(() -> {
Hyunsun Moon0e058f22017-04-19 17:00:52 +09001035 log.info("Reconfigure routers for {}", osNode.hostname());
Hyunsun Moon44aac662017-02-18 02:07:01 +09001036 reconfigureRouters();
1037 });
1038 break;
Hyunsun Moon0d457362017-06-27 17:19:41 +09001039 case OPENSTACK_NODE_CREATED:
Hyunsun Moon44aac662017-02-18 02:07:01 +09001040 default:
1041 break;
1042 }
1043 }
1044
1045 private void reconfigureRouters() {
1046 osRouterService.routers().forEach(osRouter -> {
1047 routerUpdated(osRouter);
1048 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
1049 routerIfaceAdded(osRouter, iface);
1050 });
1051 });
1052 }
1053 }
sangho072c4dd2017-05-17 10:45:21 +09001054
1055 private class InternalInstancePortListener implements InstancePortListener {
1056
1057 @Override
1058 public boolean isRelevant(InstancePortEvent event) {
1059 InstancePort instPort = event.subject();
1060 return mastershipService.isLocalMaster(instPort.deviceId());
1061 }
1062
1063 @Override
1064 public void event(InstancePortEvent event) {
1065 InstancePort instPort = event.subject();
1066 switch (event.type()) {
sangho072c4dd2017-05-17 10:45:21 +09001067 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Liec5c32b2018-07-13 14:28:58 +09001068 case OPENSTACK_INSTANCE_PORT_UPDATED:
1069 log.info("RoutingHandler: Instance port detected MAC:{} IP:{}",
1070 instPort.macAddress(),
1071 instPort.ipAddress());
1072
1073 eventExecutor.execute(() -> instPortDetected(event.subject()));
1074
sangho072c4dd2017-05-17 10:45:21 +09001075 break;
1076 case OPENSTACK_INSTANCE_PORT_VANISHED:
Jian Liec5c32b2018-07-13 14:28:58 +09001077 log.info("RoutingHandler: Instance port vanished MAC:{} IP:{}",
1078 instPort.macAddress(),
1079 instPort.ipAddress());
1080
1081 eventExecutor.execute(() -> instPortRemoved(event.subject()));
1082
1083 break;
1084 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
1085 log.info("RoutingHandler: Migration started for MAC:{} IP:{}",
1086 instPort.macAddress(),
1087 instPort.ipAddress());
1088
1089 eventExecutor.execute(() -> instPortDetected(instPort));
1090
sangho072c4dd2017-05-17 10:45:21 +09001091 break;
Jian Li24ec59f2018-05-23 19:01:25 +09001092 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
Jian Liec5c32b2018-07-13 14:28:58 +09001093 log.info("RoutingHandler: Migration finished for MAC:{} IP:{}",
1094 instPort.macAddress(),
1095 instPort.ipAddress());
Jian Li24ec59f2018-05-23 19:01:25 +09001096 eventExecutor.execute(() -> {
Jian Li24ec59f2018-05-23 19:01:25 +09001097 // TODO: need to reconfigure rules to point to update VM
1098 });
Jian Liec5c32b2018-07-13 14:28:58 +09001099
Jian Li24ec59f2018-05-23 19:01:25 +09001100 break;
sangho072c4dd2017-05-17 10:45:21 +09001101 default:
1102 break;
1103 }
1104 }
1105
1106 private void instPortDetected(InstancePort instPort) {
daniel park796c2eb2018-03-22 17:01:51 +09001107 if (osNetworkAdminService.network(instPort.networkId()).getNetworkType() == NetworkType.FLAT) {
1108 return;
1109 }
Daniel Parkc64b4c62018-05-09 18:13:39 +09001110
1111 if (useStatefulSnat) {
1112 osNodeService.completeNodes(GATEWAY)
1113 .forEach(gwNode -> setRulesForSnatIngressRule(
1114 gwNode.intgBridge(),
1115 Long.parseLong(osNetworkAdminService
1116 .network(instPort.networkId()).getProviderSegID()),
1117 IpPrefix.valueOf(instPort.ipAddress(), 32),
1118 instPort.deviceId(), true));
1119 }
sangho072c4dd2017-05-17 10:45:21 +09001120 }
1121
1122 private void instPortRemoved(InstancePort instPort) {
daniel park796c2eb2018-03-22 17:01:51 +09001123 if (osNetworkAdminService.network(instPort.networkId()).getNetworkType() == NetworkType.FLAT) {
1124 return;
1125 }
Daniel Parkc64b4c62018-05-09 18:13:39 +09001126
1127 if (useStatefulSnat) {
1128 osNodeService.completeNodes(GATEWAY)
1129 .forEach(gwNode -> setRulesForSnatIngressRule(
1130 gwNode.intgBridge(),
1131 Long.parseLong(osNetworkAdminService
1132 .network(instPort.networkId()).getProviderSegID()),
1133 IpPrefix.valueOf(instPort.ipAddress(), 32),
1134 instPort.deviceId(), false));
1135 }
sangho072c4dd2017-05-17 10:45:21 +09001136 }
1137 }
Hyunsun Moon44aac662017-02-18 02:07:01 +09001138}