blob: edc9e09be5d908d66777ddc8836a40e9b3183e91 [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;
Jian Li32b03622018-11-06 17:54:24 +0900103import static org.openstack4j.model.network.NetworkType.FLAT;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900104
105/**
106 * Handles OpenStack router events.
107 */
108@Component(immediate = true)
109public class OpenstackRoutingHandler {
110
111 private final Logger log = LoggerFactory.getLogger(getClass());
112
113 private static final String MSG_ENABLED = "Enabled ";
114 private static final String MSG_DISABLED = "Disabled ";
daniel parkee8700b2017-05-11 15:50:03 +0900115 private static final String ERR_UNSUPPORTED_NET_TYPE = "Unsupported network type";
sanghoe765ce22017-06-23 17:54:57 +0900116 private static final boolean USE_STATEFUL_SNAT = false;
117
118 @Property(name = "useStatefulSnat", boolValue = USE_STATEFUL_SNAT,
119 label = "Use Stateful SNAT for source NATing")
120 private boolean useStatefulSnat = USE_STATEFUL_SNAT;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900121
122 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
123 protected CoreService coreService;
124
125 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
126 protected LeadershipService leadershipService;
127
128 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
129 protected ClusterService clusterService;
130
131 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900132 protected OpenstackNodeService osNodeService;
133
134 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
daniel park32b42202018-03-14 16:53:44 +0900135 protected OpenstackNetworkAdminService osNetworkAdminService;
136
137 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900138 protected OpenstackRouterService osRouterService;
139
daniel parkee8700b2017-05-11 15:50:03 +0900140 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho072c4dd2017-05-17 10:45:21 +0900141 protected InstancePortService instancePortService;
142
143 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
144 protected DeviceService deviceService;
145
146 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sanghodc375372017-06-08 10:41:30 +0900147 protected OpenstackFlowRuleService osFlowRuleService;
148
sangho072c4dd2017-05-17 10:45:21 +0900149 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
150 protected MastershipService mastershipService;
151
152 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
153 protected DriverService driverService;
154
sanghoe765ce22017-06-23 17:54:57 +0900155 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
156 protected ComponentConfigService configService;
157
Hyunsun Moon44aac662017-02-18 02:07:01 +0900158 private final ExecutorService eventExecutor = newSingleThreadScheduledExecutor(
159 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
160 private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
161 private final OpenstackRouterListener osRouterListener = new InternalRouterEventListener();
sangho072c4dd2017-05-17 10:45:21 +0900162 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900163
164 private ApplicationId appId;
165 private NodeId localNodeId;
166
167 @Activate
168 protected void activate() {
169 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
170 localNodeId = clusterService.getLocalNode().id();
171 leadershipService.runForLeadership(appId.name());
172 osNodeService.addListener(osNodeListener);
173 osRouterService.addListener(osRouterListener);
sangho072c4dd2017-05-17 10:45:21 +0900174 instancePortService.addListener(instancePortListener);
sanghoe765ce22017-06-23 17:54:57 +0900175 configService.registerProperties(getClass());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900176
177 log.info("Started");
178 }
179
180 @Deactivate
181 protected void deactivate() {
182 osRouterService.removeListener(osRouterListener);
183 osNodeService.removeListener(osNodeListener);
sangho072c4dd2017-05-17 10:45:21 +0900184 instancePortService.removeListener(instancePortListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900185 leadershipService.withdraw(appId.name());
sanghoe765ce22017-06-23 17:54:57 +0900186 configService.unregisterProperties(getClass(), false);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900187 eventExecutor.shutdown();
188
189 log.info("Stopped");
190 }
191
sanghoe765ce22017-06-23 17:54:57 +0900192 @Modified
193 protected void modified(ComponentContext context) {
194 Dictionary<?, ?> properties = context.getProperties();
195 Boolean flag;
196
197 flag = Tools.isPropertyEnabled(properties, "useStatefulSnat");
198 if (flag == null) {
199 log.info("useStatefulSnat is not configured, " +
200 "using current value of {}", useStatefulSnat);
201 } else {
202 useStatefulSnat = flag;
203 log.info("Configured. useStatefulSnat is {}",
204 useStatefulSnat ? "enabled" : "disabled");
205 }
206
207 resetSnatRules();
208 }
209
Hyunsun Moon44aac662017-02-18 02:07:01 +0900210 private void routerUpdated(Router osRouter) {
211 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
Frank Wang245a6822017-06-14 09:51:35 +0800212 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
Jian Liedc8b762018-03-22 15:42:00 +0900213 Network network = osNetworkAdminService.network(osNetworkAdminService.subnet(iface.getSubnetId())
Frank Wang245a6822017-06-14 09:51:35 +0800214 .getNetworkId());
215 setRouterAdminRules(network.getProviderSegID(), network.getNetworkType(), !osRouter.isAdminStateUp());
216 });
217
Jian Liedc8b762018-03-22 15:42:00 +0900218 ExternalPeerRouter externalPeerRouter = osNetworkAdminService.externalPeerRouter(exGateway);
Jian Li5e2ad4a2018-07-16 13:40:53 +0900219 VlanId vlanId = externalPeerRouter == null ? VlanId.NONE : externalPeerRouter.vlanId();
daniel park576969a2018-03-09 07:07:41 +0900220
Hyunsun Moon44aac662017-02-18 02:07:01 +0900221 if (exGateway == null) {
Daniel Park613ac372018-06-28 14:30:11 +0900222 deleteUnassociatedExternalPeerRouter();
daniel park576969a2018-03-09 07:07:41 +0900223 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> setSourceNat(iface, false));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900224 } else {
daniel park32b42202018-03-14 16:53:44 +0900225 osNetworkAdminService.deriveExternalPeerRouterMac(exGateway, osRouter, vlanId);
daniel park576969a2018-03-09 07:07:41 +0900226 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface ->
227 setSourceNat(iface, exGateway.isEnableSnat()));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900228 }
229 }
230
Daniel Park613ac372018-06-28 14:30:11 +0900231 private void deleteUnassociatedExternalPeerRouter() {
232 log.trace("Deleting unassociated external peer router");
233
234 try {
235 Set<String> routerIps = Sets.newConcurrentHashSet();
236
237 osRouterService.routers().stream()
238 .filter(router -> getGatewayIpAddress(router) != null)
239 .map(router -> getGatewayIpAddress(router).toString())
240 .forEach(routerIps::add);
241
242 osNetworkAdminService.externalPeerRouters().stream()
243 .filter(externalPeerRouter ->
Jian Li5e2ad4a2018-07-16 13:40:53 +0900244 !routerIps.contains(externalPeerRouter.ipAddress().toString()))
Daniel Park613ac372018-06-28 14:30:11 +0900245 .forEach(externalPeerRouter -> {
246 osNetworkAdminService
Jian Li5e2ad4a2018-07-16 13:40:53 +0900247 .deleteExternalPeerRouter(externalPeerRouter.ipAddress().toString());
Daniel Park613ac372018-06-28 14:30:11 +0900248 log.trace("Deleted unassociated external peer router {}",
Jian Li5e2ad4a2018-07-16 13:40:53 +0900249 externalPeerRouter.ipAddress().toString());
Daniel Park613ac372018-06-28 14:30:11 +0900250 });
251 } catch (Exception e) {
252 log.error("Exception occurred because of {}", e.toString());
253 }
254 }
255
Frank Wang245a6822017-06-14 09:51:35 +0800256 private void routerRemove(Router osRouter) {
257 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
Jian Liedc8b762018-03-22 15:42:00 +0900258 Network network = osNetworkAdminService.network(osNetworkAdminService.subnet(iface.getSubnetId())
Frank Wang245a6822017-06-14 09:51:35 +0800259 .getNetworkId());
260 setRouterAdminRules(network.getProviderSegID(), network.getNetworkType(), false);
261 });
262 }
263
Hyunsun Moon44aac662017-02-18 02:07:01 +0900264 private void routerIfaceAdded(Router osRouter, RouterInterface osRouterIface) {
Jian Liedc8b762018-03-22 15:42:00 +0900265 Subnet osSubnet = osNetworkAdminService.subnet(osRouterIface.getSubnetId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900266 if (osSubnet == null) {
267 final String error = String.format(
Jian Li71670d12018-03-02 21:31:07 +0900268 "Failed to set flows for router %s: subnet %s does not exist",
Hyunsun Moon44aac662017-02-18 02:07:01 +0900269 osRouterIface.getId(),
270 osRouterIface.getSubnetId());
271 throw new IllegalStateException(error);
272 }
Frank Wang245a6822017-06-14 09:51:35 +0800273
274 if (!osRouter.isAdminStateUp()) {
Jian Liedc8b762018-03-22 15:42:00 +0900275 Network network = osNetworkAdminService.network(osSubnet.getNetworkId());
Frank Wang245a6822017-06-14 09:51:35 +0800276 setRouterAdminRules(network.getProviderSegID(), network.getNetworkType(), true);
277 }
278
Hyunsun Moon44aac662017-02-18 02:07:01 +0900279 setInternalRoutes(osRouter, osSubnet, true);
Daniel Park51f9d1e2018-10-26 13:39:09 +0900280 setGatewayIcmp(osSubnet, osRouter, true);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900281 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
282 if (exGateway != null && exGateway.isEnableSnat()) {
daniel park576969a2018-03-09 07:07:41 +0900283 setSourceNat(osRouterIface, true);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900284 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900285 log.info("Connected subnet({}) to {}", osSubnet.getCidr(), osRouter.getName());
286 }
287
288 private void routerIfaceRemoved(Router osRouter, RouterInterface osRouterIface) {
Jian Liedc8b762018-03-22 15:42:00 +0900289 Subnet osSubnet = osNetworkAdminService.subnet(osRouterIface.getSubnetId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900290 if (osSubnet == null) {
291 final String error = String.format(
Jian Li71670d12018-03-02 21:31:07 +0900292 "Failed to set flows for router %s: subnet %s does not exist",
Hyunsun Moon44aac662017-02-18 02:07:01 +0900293 osRouterIface.getId(),
294 osRouterIface.getSubnetId());
295 throw new IllegalStateException(error);
296 }
297
Frank Wang245a6822017-06-14 09:51:35 +0800298 if (!osRouter.isAdminStateUp()) {
Jian Liedc8b762018-03-22 15:42:00 +0900299 Network network = osNetworkAdminService.network(osSubnet.getNetworkId());
Frank Wang245a6822017-06-14 09:51:35 +0800300 setRouterAdminRules(network.getProviderSegID(), network.getNetworkType(), false);
301 }
302
Hyunsun Moon44aac662017-02-18 02:07:01 +0900303 setInternalRoutes(osRouter, osSubnet, false);
Daniel Park51f9d1e2018-10-26 13:39:09 +0900304 setGatewayIcmp(osSubnet, osRouter, false);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900305 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
306 if (exGateway != null && exGateway.isEnableSnat()) {
daniel park576969a2018-03-09 07:07:41 +0900307 setSourceNat(osRouterIface, false);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900308 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900309 log.info("Disconnected subnet({}) from {}", osSubnet.getCidr(), osRouter.getName());
310 }
311
daniel park576969a2018-03-09 07:07:41 +0900312 private void setSourceNat(RouterInterface routerIface, boolean install) {
Jian Liedc8b762018-03-22 15:42:00 +0900313 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
314 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900315
Hyunsun Moon0d457362017-06-27 17:19:41 +0900316 osNodeService.completeNodes(COMPUTE).forEach(cNode -> {
317 setRulesToGateway(cNode, osNet.getProviderSegID(),
318 IpPrefix.valueOf(osSubnet.getCidr()), osNet.getNetworkType(),
319 install);
320 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900321
sanghoe765ce22017-06-23 17:54:57 +0900322 if (useStatefulSnat) {
323 setStatefulSnatRules(routerIface, install);
324 } else {
325 setReactiveSnatRules(routerIface, install);
326 }
327
328 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
329 log.info(updateStr + "external access for subnet({})", osSubnet.getCidr());
330 }
331
332 private void setStatefulSnatRules(RouterInterface routerIface, boolean install) {
Jian Liedc8b762018-03-22 15:42:00 +0900333 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
334 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
sanghoe765ce22017-06-23 17:54:57 +0900335
Jian Li32b03622018-11-06 17:54:24 +0900336 if (osNet.getNetworkType() == FLAT) {
daniel park796c2eb2018-03-22 17:01:51 +0900337 return;
338 }
339
sanghoe765ce22017-06-23 17:54:57 +0900340 Optional<Router> osRouter = osRouterService.routers().stream()
341 .filter(router -> osRouterService.routerInterfaces(routerIface.getId()) != null)
342 .findAny();
343
344 if (!osRouter.isPresent()) {
345 log.error("Cannot find a router for router interface {} ", routerIface);
346 return;
347 }
348 IpAddress natAddress = getGatewayIpAddress(osRouter.get());
sangho072c4dd2017-05-17 10:45:21 +0900349 if (natAddress == null) {
350 return;
351 }
Jian Liedc8b762018-03-22 15:42:00 +0900352 String netId = osNetworkAdminService.subnet(routerIface.getSubnetId()).getNetworkId();
sangho072c4dd2017-05-17 10:45:21 +0900353
354 osNodeService.completeNodes(OpenstackNode.NodeType.GATEWAY)
355 .forEach(gwNode -> {
daniel park576969a2018-03-09 07:07:41 +0900356 instancePortService.instancePorts(netId)
Jian Lic2403592018-07-18 12:56:45 +0900357 .stream()
358 .filter(port -> port.state() == ACTIVE)
daniel park576969a2018-03-09 07:07:41 +0900359 .forEach(port -> setRulesForSnatIngressRule(gwNode.intgBridge(),
sangho072c4dd2017-05-17 10:45:21 +0900360 Long.parseLong(osNet.getProviderSegID()),
361 IpPrefix.valueOf(port.ipAddress(), 32),
362 port.deviceId(),
363 install));
364
365 setOvsNatIngressRule(gwNode.intgBridge(),
366 IpPrefix.valueOf(natAddress, 32),
367 Constants.DEFAULT_EXTERNAL_ROUTER_MAC, install);
368 setOvsNatEgressRule(gwNode.intgBridge(),
369 natAddress, Long.parseLong(osNet.getProviderSegID()),
370 gwNode.patchPortNum(), install);
371 });
sanghoe765ce22017-06-23 17:54:57 +0900372 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900373
sanghoe765ce22017-06-23 17:54:57 +0900374 private void setReactiveSnatRules(RouterInterface routerIface, boolean install) {
Jian Liedc8b762018-03-22 15:42:00 +0900375 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
376 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
sanghoe765ce22017-06-23 17:54:57 +0900377
378 osNodeService.completeNodes(GATEWAY)
379 .forEach(gwNode -> setRulesToController(
380 gwNode.intgBridge(),
381 osNet.getProviderSegID(),
382 IpPrefix.valueOf(osSubnet.getCidr()),
383 osNet.getNetworkType(),
384 install));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900385 }
386
sangho072c4dd2017-05-17 10:45:21 +0900387 private IpAddress getGatewayIpAddress(Router osRouter) {
388
Daniel Park613ac372018-06-28 14:30:11 +0900389 if (osRouter.getExternalGatewayInfo() == null) {
390 return null;
391 }
Jian Liedc8b762018-03-22 15:42:00 +0900392 String extNetId = osNetworkAdminService.network(osRouter.getExternalGatewayInfo().getNetworkId()).getId();
393 Optional<Subnet> extSubnet = osNetworkAdminService.subnets().stream()
sangho072c4dd2017-05-17 10:45:21 +0900394 .filter(subnet -> subnet.getNetworkId().equals(extNetId))
395 .findAny();
396
397 if (!extSubnet.isPresent()) {
398 log.error("Cannot find externel subnet for the router");
399 return null;
400 }
401
402 return IpAddress.valueOf(extSubnet.get().getGateway());
403 }
404
sanghoe765ce22017-06-23 17:54:57 +0900405 private void resetSnatRules() {
406 if (useStatefulSnat) {
407 osRouterService.routerInterfaces().forEach(
408 routerIface -> {
409 setReactiveSnatRules(routerIface, false);
410 setStatefulSnatRules(routerIface, true);
411 }
412 );
413 } else {
414 osRouterService.routerInterfaces().forEach(
415 routerIface -> {
416 setStatefulSnatRules(routerIface, false);
417 setReactiveSnatRules(routerIface, true);
418 }
419 );
420 }
421 }
422
Daniel Park51f9d1e2018-10-26 13:39:09 +0900423 private void setGatewayIcmp(Subnet osSubnet, Router osRouter, boolean install) {
daniel parkb5817102018-02-15 00:18:51 +0900424 OpenstackNode sourceNatGateway = osNodeService.completeNodes(GATEWAY).stream().findFirst().orElse(null);
425
426 if (sourceNatGateway == null) {
427 return;
428 }
429
Hyunsun Moon44aac662017-02-18 02:07:01 +0900430 if (Strings.isNullOrEmpty(osSubnet.getGateway())) {
431 // do nothing if no gateway is set
432 return;
433 }
434
435 // take ICMP request to a subnet gateway through gateway node group
Jian Liedc8b762018-03-22 15:42:00 +0900436 Network network = osNetworkAdminService.network(osSubnet.getNetworkId());
Daniel Park51f9d1e2018-10-26 13:39:09 +0900437 Set<Subnet> routableSubnets = routableSubnets(osRouter, osSubnet.getId());
438
daniel parkee8700b2017-05-11 15:50:03 +0900439 switch (network.getNetworkType()) {
440 case VXLAN:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900441 osNodeService.completeNodes(COMPUTE).stream()
442 .filter(cNode -> cNode.dataIp() != null)
Daniel Park51f9d1e2018-10-26 13:39:09 +0900443 .forEach(cNode -> setRulesToGatewayWithRoutableSubnets(
Hyunsun Moon0d457362017-06-27 17:19:41 +0900444 cNode,
daniel parkb5817102018-02-15 00:18:51 +0900445 sourceNatGateway,
daniel parkee8700b2017-05-11 15:50:03 +0900446 network.getProviderSegID(),
Daniel Park51f9d1e2018-10-26 13:39:09 +0900447 osSubnet,
448 routableSubnets,
daniel parkee8700b2017-05-11 15:50:03 +0900449 NetworkMode.VXLAN,
450 install));
451 break;
452 case VLAN:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900453 osNodeService.completeNodes(COMPUTE).stream()
454 .filter(cNode -> cNode.vlanPortNum() != null)
Daniel Park51f9d1e2018-10-26 13:39:09 +0900455 .forEach(cNode -> setRulesToGatewayWithRoutableSubnets(
Hyunsun Moon0d457362017-06-27 17:19:41 +0900456 cNode,
daniel parkb5817102018-02-15 00:18:51 +0900457 sourceNatGateway,
daniel parkee8700b2017-05-11 15:50:03 +0900458 network.getProviderSegID(),
Daniel Park51f9d1e2018-10-26 13:39:09 +0900459 osSubnet,
460 routableSubnets,
daniel parkee8700b2017-05-11 15:50:03 +0900461 NetworkMode.VLAN,
462 install));
463 break;
464 default:
Jian Li71670d12018-03-02 21:31:07 +0900465 final String error = String.format("%s %s",
466 ERR_UNSUPPORTED_NET_TYPE,
daniel parkee8700b2017-05-11 15:50:03 +0900467 network.getNetworkType().toString());
468 throw new IllegalStateException(error);
469 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900470
471 IpAddress gatewayIp = IpAddress.valueOf(osSubnet.getGateway());
daniel park576969a2018-03-09 07:07:41 +0900472 osNodeService.completeNodes(GATEWAY).forEach(gNode ->
Hyunsun Moon0d457362017-06-27 17:19:41 +0900473 setGatewayIcmpRule(
474 gatewayIp,
475 gNode.intgBridge(),
daniel park576969a2018-03-09 07:07:41 +0900476 install));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900477
478 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
479 log.debug(updateStr + "ICMP to {}", osSubnet.getGateway());
480 }
481
482 private void setInternalRoutes(Router osRouter, Subnet updatedSubnet, boolean install) {
Jian Liedc8b762018-03-22 15:42:00 +0900483 Network updatedNetwork = osNetworkAdminService.network(updatedSubnet.getNetworkId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900484 Set<Subnet> routableSubnets = routableSubnets(osRouter, updatedSubnet.getId());
Jian Lib6969502018-10-30 20:38:07 +0900485 String updatedSegmentId = getSegmentId(updatedSubnet);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900486
487 // installs rule from/to my subnet intentionally to fix ICMP failure
488 // to my subnet gateway if no external gateway added to the router
Hyunsun Moon0d457362017-06-27 17:19:41 +0900489 osNodeService.completeNodes(COMPUTE).forEach(cNode -> {
490 setInternalRouterRules(
491 cNode.intgBridge(),
Jian Lib6969502018-10-30 20:38:07 +0900492 updatedSegmentId,
493 updatedSegmentId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900494 IpPrefix.valueOf(updatedSubnet.getCidr()),
495 IpPrefix.valueOf(updatedSubnet.getCidr()),
496 updatedNetwork.getNetworkType(),
497 install
498 );
Hyunsun Moon44aac662017-02-18 02:07:01 +0900499
Hyunsun Moon0d457362017-06-27 17:19:41 +0900500 routableSubnets.forEach(subnet -> {
501 setInternalRouterRules(
502 cNode.intgBridge(),
Jian Lib6969502018-10-30 20:38:07 +0900503 updatedSegmentId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900504 getSegmentId(subnet),
505 IpPrefix.valueOf(updatedSubnet.getCidr()),
506 IpPrefix.valueOf(subnet.getCidr()),
507 updatedNetwork.getNetworkType(),
508 install
509 );
510 setInternalRouterRules(
511 cNode.intgBridge(),
512 getSegmentId(subnet),
Jian Lib6969502018-10-30 20:38:07 +0900513 updatedSegmentId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900514 IpPrefix.valueOf(subnet.getCidr()),
515 IpPrefix.valueOf(updatedSubnet.getCidr()),
516 updatedNetwork.getNetworkType(),
517 install
518 );
519 });
520 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900521
daniel parkee8700b2017-05-11 15:50:03 +0900522
Hyunsun Moon44aac662017-02-18 02:07:01 +0900523 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
524 routableSubnets.forEach(subnet -> log.debug(
525 updateStr + "route between subnet:{} and subnet:{}",
526 subnet.getCidr(),
527 updatedSubnet.getCidr()));
528 }
529
530 private Set<Subnet> routableSubnets(Router osRouter, String osSubnetId) {
531 Set<Subnet> osSubnets = osRouterService.routerInterfaces(osRouter.getId())
532 .stream()
533 .filter(iface -> !Objects.equals(iface.getSubnetId(), osSubnetId))
Jian Liedc8b762018-03-22 15:42:00 +0900534 .map(iface -> osNetworkAdminService.subnet(iface.getSubnetId()))
Hyunsun Moon44aac662017-02-18 02:07:01 +0900535 .collect(Collectors.toSet());
536 return ImmutableSet.copyOf(osSubnets);
537 }
538
daniel parkee8700b2017-05-11 15:50:03 +0900539 private String getSegmentId(Subnet osSubnet) {
Jian Liedc8b762018-03-22 15:42:00 +0900540 return osNetworkAdminService.network(osSubnet.getNetworkId()).getProviderSegID();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900541 }
542
543 private void setGatewayIcmpRule(IpAddress gatewayIp, DeviceId deviceId, boolean install) {
544 TrafficSelector selector = DefaultTrafficSelector.builder()
545 .matchEthType(Ethernet.TYPE_IPV4)
546 .matchIPProtocol(IPv4.PROTOCOL_ICMP)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900547 .matchIPDst(gatewayIp.getIp4Address().toIpPrefix())
Hyunsun Moon44aac662017-02-18 02:07:01 +0900548 .build();
549
550 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Li4d5c5c32018-04-02 16:38:18 +0900551 .punt()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900552 .build();
553
sanghodc375372017-06-08 10:41:30 +0900554 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900555 appId,
556 deviceId,
557 selector,
558 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900559 PRIORITY_ICMP_RULE,
sanghodc375372017-06-08 10:41:30 +0900560 Constants.GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900561 install);
562 }
563
daniel parkee8700b2017-05-11 15:50:03 +0900564 private void setInternalRouterRules(DeviceId deviceId, String srcSegmentId, String dstSegmentId,
565 IpPrefix srcSubnet, IpPrefix dstSubnet,
566 NetworkType networkType, boolean install) {
567 TrafficSelector selector;
568 TrafficTreatment treatment;
569 switch (networkType) {
570 case VXLAN:
571 selector = DefaultTrafficSelector.builder()
572 .matchEthType(Ethernet.TYPE_IPV4)
573 .matchTunnelId(Long.parseLong(srcSegmentId))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900574 .matchIPSrc(srcSubnet.getIp4Prefix())
575 .matchIPDst(dstSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900576 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900577
daniel parkee8700b2017-05-11 15:50:03 +0900578 treatment = DefaultTrafficTreatment.builder()
579 .setTunnelId(Long.parseLong(dstSegmentId))
Jian Li8abf2fe2018-06-12 18:42:30 +0900580 .transition(STAT_OUTBOUND_TABLE)
daniel parkee8700b2017-05-11 15:50:03 +0900581 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900582
sanghodc375372017-06-08 10:41:30 +0900583 osFlowRuleService.setRule(
daniel parkee8700b2017-05-11 15:50:03 +0900584 appId,
585 deviceId,
586 selector,
587 treatment,
daniel parkee8700b2017-05-11 15:50:03 +0900588 PRIORITY_INTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900589 ROUTING_TABLE,
daniel parkee8700b2017-05-11 15:50:03 +0900590 install);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900591
daniel parkee8700b2017-05-11 15:50:03 +0900592 selector = DefaultTrafficSelector.builder()
593 .matchEthType(Ethernet.TYPE_IPV4)
594 .matchTunnelId(Long.parseLong(dstSegmentId))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900595 .matchIPSrc(srcSubnet.getIp4Prefix())
596 .matchIPDst(dstSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900597 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900598
daniel parkee8700b2017-05-11 15:50:03 +0900599 treatment = DefaultTrafficTreatment.builder()
600 .setTunnelId(Long.parseLong(dstSegmentId))
Jian Li8abf2fe2018-06-12 18:42:30 +0900601 .transition(STAT_OUTBOUND_TABLE)
daniel parkee8700b2017-05-11 15:50:03 +0900602 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900603
sanghodc375372017-06-08 10:41:30 +0900604 osFlowRuleService.setRule(
daniel parkee8700b2017-05-11 15:50:03 +0900605 appId,
606 deviceId,
607 selector,
608 treatment,
daniel parkee8700b2017-05-11 15:50:03 +0900609 PRIORITY_INTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900610 ROUTING_TABLE,
daniel parkee8700b2017-05-11 15:50:03 +0900611 install);
612 break;
613 case VLAN:
614 selector = DefaultTrafficSelector.builder()
615 .matchEthType(Ethernet.TYPE_IPV4)
616 .matchVlanId(VlanId.vlanId(srcSegmentId))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900617 .matchIPSrc(srcSubnet.getIp4Prefix())
618 .matchIPDst(dstSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900619 .build();
620
621 treatment = DefaultTrafficTreatment.builder()
622 .setVlanId(VlanId.vlanId(dstSegmentId))
Jian Li8abf2fe2018-06-12 18:42:30 +0900623 .transition(STAT_OUTBOUND_TABLE)
daniel parkee8700b2017-05-11 15:50:03 +0900624 .build();
625
sanghodc375372017-06-08 10:41:30 +0900626 osFlowRuleService.setRule(
daniel parkee8700b2017-05-11 15:50:03 +0900627 appId,
628 deviceId,
629 selector,
630 treatment,
daniel parkee8700b2017-05-11 15:50:03 +0900631 PRIORITY_INTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900632 ROUTING_TABLE,
daniel parkee8700b2017-05-11 15:50:03 +0900633 install);
634
635 selector = DefaultTrafficSelector.builder()
636 .matchEthType(Ethernet.TYPE_IPV4)
637 .matchVlanId(VlanId.vlanId(dstSegmentId))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900638 .matchIPSrc(srcSubnet.getIp4Prefix())
639 .matchIPDst(dstSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900640 .build();
641
642 treatment = DefaultTrafficTreatment.builder()
643 .setVlanId(VlanId.vlanId(dstSegmentId))
Jian Li8abf2fe2018-06-12 18:42:30 +0900644 .transition(STAT_OUTBOUND_TABLE)
daniel parkee8700b2017-05-11 15:50:03 +0900645 .build();
646
sanghodc375372017-06-08 10:41:30 +0900647 osFlowRuleService.setRule(
daniel parkee8700b2017-05-11 15:50:03 +0900648 appId,
649 deviceId,
650 selector,
651 treatment,
daniel parkee8700b2017-05-11 15:50:03 +0900652 PRIORITY_INTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900653 ROUTING_TABLE,
daniel parkee8700b2017-05-11 15:50:03 +0900654 install);
655 break;
656 default:
Jian Li71670d12018-03-02 21:31:07 +0900657 final String error = String.format("%s %s",
658 ERR_UNSUPPORTED_NET_TYPE,
daniel parkee8700b2017-05-11 15:50:03 +0900659 networkType.toString());
660 throw new IllegalStateException(error);
661 }
662
Hyunsun Moon44aac662017-02-18 02:07:01 +0900663 }
664
Hyunsun Moon0d457362017-06-27 17:19:41 +0900665 private void setRulesToGateway(OpenstackNode osNode, String segmentId, IpPrefix srcSubnet,
daniel parkee8700b2017-05-11 15:50:03 +0900666 NetworkType networkType, boolean install) {
daniel parkb5817102018-02-15 00:18:51 +0900667 OpenstackNode sourceNatGateway = osNodeService.completeNodes(GATEWAY).stream().findFirst().orElse(null);
668
669 if (sourceNatGateway == null) {
670 return;
671 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900672
daniel parkee8700b2017-05-11 15:50:03 +0900673 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
674 .matchEthType(Ethernet.TYPE_IPV4)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900675 .matchIPSrc(srcSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900676 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
677
678 switch (networkType) {
679 case VXLAN:
680 sBuilder.matchTunnelId(Long.parseLong(segmentId));
daniel parkee8700b2017-05-11 15:50:03 +0900681 break;
682 case VLAN:
683 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
daniel parkee8700b2017-05-11 15:50:03 +0900684 break;
685 default:
Jian Li71670d12018-03-02 21:31:07 +0900686 final String error = String.format("%s %s",
687 ERR_UNSUPPORTED_NET_TYPE,
daniel parkee8700b2017-05-11 15:50:03 +0900688 networkType.toString());
689 throw new IllegalStateException(error);
690 }
691
Daniel Parkc64b4c62018-05-09 18:13:39 +0900692 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
693
694 switch (networkType) {
695 case VXLAN:
696 tBuilder.extension(buildExtension(
697 deviceService,
698 osNode.intgBridge(),
699 sourceNatGateway.dataIp().getIp4Address()),
700 osNode.intgBridge())
701 .setOutput(osNode.tunnelPortNum());
702 break;
703
704 case VLAN:
705 tBuilder.setOutput(osNode.vlanPortNum());
706 break;
707
708 default:
709 break;
710 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900711
sanghodc375372017-06-08 10:41:30 +0900712 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900713 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900714 osNode.intgBridge(),
daniel parkee8700b2017-05-11 15:50:03 +0900715 sBuilder.build(),
Daniel Parkc64b4c62018-05-09 18:13:39 +0900716 tBuilder.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900717 PRIORITY_EXTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900718 ROUTING_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900719 install);
720 }
721
sangho072c4dd2017-05-17 10:45:21 +0900722 private void setRulesForSnatIngressRule(DeviceId deviceId, Long vni, IpPrefix destVmIp,
723 DeviceId dstDeviceId, boolean install) {
724
725 TrafficSelector selector = DefaultTrafficSelector.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900726 .matchEthType(Ethernet.TYPE_IPV4)
sangho072c4dd2017-05-17 10:45:21 +0900727 .matchIPDst(destVmIp)
728 .build();
Hyunsun Moon0d457362017-06-27 17:19:41 +0900729
sangho072c4dd2017-05-17 10:45:21 +0900730 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
731 .setTunnelId(vni)
732 .extension(buildExtension(
733 deviceService,
734 deviceId,
735 osNodeService.node(dstDeviceId).dataIp().getIp4Address()),
736 deviceId)
737 .setOutput(osNodeService.node(deviceId).tunnelPortNum())
738 .build();
daniel parkee8700b2017-05-11 15:50:03 +0900739
sanghodc375372017-06-08 10:41:30 +0900740 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900741 appId,
sangho072c4dd2017-05-17 10:45:21 +0900742 deviceId,
743 selector,
744 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900745 PRIORITY_EXTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900746 Constants.GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900747 install);
748 }
749
Daniel Park51f9d1e2018-10-26 13:39:09 +0900750 private void setRulesToGatewayWithRoutableSubnets(OpenstackNode osNode, OpenstackNode sourceNatGateway,
751 String segmentId, Subnet updatedSubnet,
752 Set<Subnet> routableSubnets, NetworkMode networkMode,
753 boolean install) {
754 //At first we install flow rules to gateway with segId and gatewayIp of updated subnet
755 setRulesToGatewayWithDstIp(osNode, sourceNatGateway, segmentId, IpAddress.valueOf(updatedSubnet.getGateway()),
756 networkMode, install);
757
758 routableSubnets.forEach(subnet -> {
759 setRulesToGatewayWithDstIp(osNode, sourceNatGateway,
760 segmentId, IpAddress.valueOf(subnet.getGateway()),
761 networkMode, install);
762
763 Network network = osNetworkAdminService.network(subnet.getNetworkId());
764 setRulesToGatewayWithDstIp(osNode, sourceNatGateway,
765 network.getProviderSegID(), IpAddress.valueOf(updatedSubnet.getGateway()),
766 networkMode, install);
767 });
768 }
769
daniel parkb5817102018-02-15 00:18:51 +0900770 private void setRulesToGatewayWithDstIp(OpenstackNode osNode, OpenstackNode sourceNatGateway,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900771 String segmentId, IpAddress dstIp,
772 NetworkMode networkMode, boolean install) {
Daniel Parkc64b4c62018-05-09 18:13:39 +0900773 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
774 .matchEthType(Ethernet.TYPE_IPV4)
775 .matchIPDst(dstIp.getIp4Address().toIpPrefix());
776
Daniel Parkc64b4c62018-05-09 18:13:39 +0900777 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
778
779 switch (networkMode) {
780 case VXLAN:
Daniel Park51f9d1e2018-10-26 13:39:09 +0900781 sBuilder.matchTunnelId(Long.parseLong(segmentId));
Daniel Parkc64b4c62018-05-09 18:13:39 +0900782 tBuilder.extension(buildExtension(
daniel parkb5817102018-02-15 00:18:51 +0900783 deviceService,
784 osNode.intgBridge(),
785 sourceNatGateway.dataIp().getIp4Address()),
786 osNode.intgBridge())
Daniel Parkc64b4c62018-05-09 18:13:39 +0900787 .setOutput(osNode.tunnelPortNum());
788 break;
789
790 case VLAN:
Daniel Park51f9d1e2018-10-26 13:39:09 +0900791 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
Daniel Parkc64b4c62018-05-09 18:13:39 +0900792 tBuilder.setOutput(osNode.vlanPortNum());
793 break;
794
795 default:
796 break;
797 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900798
sanghodc375372017-06-08 10:41:30 +0900799 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900800 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900801 osNode.intgBridge(),
Daniel Parkc64b4c62018-05-09 18:13:39 +0900802 sBuilder.build(),
803 tBuilder.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900804 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900805 ROUTING_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900806 install);
807 }
808
sangho072c4dd2017-05-17 10:45:21 +0900809 private void setOvsNatIngressRule(DeviceId deviceId, IpPrefix cidr, MacAddress dstMac, boolean install) {
810
811 TrafficSelector selector = DefaultTrafficSelector.builder()
812 .matchEthType(Ethernet.TYPE_IPV4)
813 .matchIPDst(cidr)
814 .build();
815
Jian Liedc8b762018-03-22 15:42:00 +0900816 ExtensionTreatment natTreatment = RulePopulatorUtil
817 .niciraConnTrackTreatmentBuilder(driverService, deviceId)
sangho072c4dd2017-05-17 10:45:21 +0900818 .commit(false)
819 .natAction(true)
820 .table((short) 0)
821 .build();
822
823 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
824 .setEthDst(dstMac)
825 .extension(natTreatment, deviceId)
826 .build();
827
828 osFlowRuleService.setRule(
829 appId,
830 deviceId,
831 selector,
832 treatment,
sanghoe765ce22017-06-23 17:54:57 +0900833 PRIORITY_STATEFUL_SNAT_RULE,
sangho072c4dd2017-05-17 10:45:21 +0900834 GW_COMMON_TABLE,
835 install);
836 }
837
838 private void setOvsNatEgressRule(DeviceId deviceId, IpAddress natAddress, long vni, PortNumber output,
839 boolean install) {
840
841 TrafficSelector selector = DefaultTrafficSelector.builder()
842 .matchEthType(Ethernet.TYPE_IPV4)
843 .matchEthDst(DEFAULT_GATEWAY_MAC)
844 .matchTunnelId(vni)
845 .build();
846
Jian Liedc8b762018-03-22 15:42:00 +0900847 ExtensionTreatment natTreatment = RulePopulatorUtil
848 .niciraConnTrackTreatmentBuilder(driverService, deviceId)
sangho072c4dd2017-05-17 10:45:21 +0900849 .commit(true)
850 .natAction(true)
851 .natIp(natAddress)
852 .build();
853
854 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
855 .extension(natTreatment, deviceId)
856 .setEthDst(DEFAULT_EXTERNAL_ROUTER_MAC)
857 .setEthSrc(DEFAULT_GATEWAY_MAC)
858 .setOutput(output)
859 .build();
860
861 osFlowRuleService.setRule(
862 appId,
863 deviceId,
864 selector,
865 treatment,
sanghoe765ce22017-06-23 17:54:57 +0900866 PRIORITY_STATEFUL_SNAT_RULE,
sangho072c4dd2017-05-17 10:45:21 +0900867 GW_COMMON_TABLE,
868 install);
869 }
870
sanghoe765ce22017-06-23 17:54:57 +0900871 private void setRulesToController(DeviceId deviceId, String segmentId, IpPrefix srcSubnet,
872 NetworkType networkType, boolean install) {
873 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
874 .matchEthType(Ethernet.TYPE_IPV4)
Daniel Parkc64b4c62018-05-09 18:13:39 +0900875 .matchIPSrc(srcSubnet)
876 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
877
sanghoe765ce22017-06-23 17:54:57 +0900878 switch (networkType) {
879 case VXLAN:
Daniel Parkc64b4c62018-05-09 18:13:39 +0900880 sBuilder.matchTunnelId(Long.parseLong(segmentId));
sanghoe765ce22017-06-23 17:54:57 +0900881 break;
882 case VLAN:
Daniel Parkc64b4c62018-05-09 18:13:39 +0900883 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
sanghoe765ce22017-06-23 17:54:57 +0900884 break;
885 default:
Jian Li71670d12018-03-02 21:31:07 +0900886 final String error = String.format("%s %s",
887 ERR_UNSUPPORTED_NET_TYPE,
sanghoe765ce22017-06-23 17:54:57 +0900888 networkType.toString());
889 throw new IllegalStateException(error);
890 }
891
Daniel Parkc64b4c62018-05-09 18:13:39 +0900892 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
sanghoe765ce22017-06-23 17:54:57 +0900893
894 if (networkType.equals(NetworkType.VLAN)) {
895 tBuilder.popVlan();
896 }
897
Jian Li4d5c5c32018-04-02 16:38:18 +0900898 tBuilder.punt();
sanghoe765ce22017-06-23 17:54:57 +0900899
900 osFlowRuleService.setRule(
901 appId,
902 deviceId,
903 sBuilder.build(),
904 tBuilder.build(),
905 PRIORITY_EXTERNAL_ROUTING_RULE,
906 GW_COMMON_TABLE,
907 install);
sanghoe765ce22017-06-23 17:54:57 +0900908 }
sangho072c4dd2017-05-17 10:45:21 +0900909
Frank Wang245a6822017-06-14 09:51:35 +0800910 private void setRouterAdminRules(String segmentId, NetworkType networkType, boolean install) {
911 TrafficTreatment treatment;
912 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
913 .matchEthType(Ethernet.TYPE_IPV4);
914
915 switch (networkType) {
916 case VXLAN:
917 sBuilder.matchTunnelId(Long.parseLong(segmentId));
918 break;
919 case VLAN:
920 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
921 break;
922 default:
Jian Li71670d12018-03-02 21:31:07 +0900923 final String error = String.format("%s %s",
924 ERR_UNSUPPORTED_NET_TYPE,
Frank Wang245a6822017-06-14 09:51:35 +0800925 networkType.toString());
926 throw new IllegalStateException(error);
927 }
928
929 treatment = DefaultTrafficTreatment.builder()
930 .drop()
931 .build();
932
933 osNodeService.completeNodes().stream()
934 .filter(osNode -> osNode.type() == COMPUTE)
935 .forEach(osNode -> {
936 osFlowRuleService.setRule(
937 appId,
938 osNode.intgBridge(),
939 sBuilder.build(),
940 treatment,
941 PRIORITY_ADMIN_RULE,
942 ROUTING_TABLE,
943 install);
944 });
945 }
946
Hyunsun Moon44aac662017-02-18 02:07:01 +0900947 private class InternalRouterEventListener implements OpenstackRouterListener {
948
949 @Override
950 public boolean isRelevant(OpenstackRouterEvent event) {
951 // do not allow to proceed without leadership
952 NodeId leader = leadershipService.getLeader(appId.name());
953 return Objects.equals(localNodeId, leader);
954 }
955
956 // FIXME only one leader in the cluster should process
957 @Override
958 public void event(OpenstackRouterEvent event) {
959 switch (event.type()) {
960 case OPENSTACK_ROUTER_CREATED:
961 log.debug("Router(name:{}, ID:{}) is created",
962 event.subject().getName(),
963 event.subject().getId());
964 eventExecutor.execute(() -> routerUpdated(event.subject()));
965 break;
966 case OPENSTACK_ROUTER_UPDATED:
967 log.debug("Router(name:{}, ID:{}) is updated",
968 event.subject().getName(),
969 event.subject().getId());
970 eventExecutor.execute(() -> routerUpdated(event.subject()));
971 break;
972 case OPENSTACK_ROUTER_REMOVED:
973 log.debug("Router(name:{}, ID:{}) is removed",
974 event.subject().getName(),
975 event.subject().getId());
Frank Wang245a6822017-06-14 09:51:35 +0800976 eventExecutor.execute(() -> routerRemove(event.subject()));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900977 break;
978 case OPENSTACK_ROUTER_INTERFACE_ADDED:
979 log.debug("Router interface {} added to router {}",
980 event.routerIface().getPortId(),
981 event.routerIface().getId());
982 eventExecutor.execute(() -> routerIfaceAdded(
983 event.subject(),
984 event.routerIface()));
985 break;
986 case OPENSTACK_ROUTER_INTERFACE_UPDATED:
987 log.debug("Router interface {} on {} updated",
988 event.routerIface().getPortId(),
989 event.routerIface().getId());
990 break;
991 case OPENSTACK_ROUTER_INTERFACE_REMOVED:
992 log.debug("Router interface {} removed from router {}",
993 event.routerIface().getPortId(),
994 event.routerIface().getId());
995 eventExecutor.execute(() -> routerIfaceRemoved(
996 event.subject(),
997 event.routerIface()));
998 break;
999 case OPENSTACK_ROUTER_GATEWAY_ADDED:
Jian Li32b03622018-11-06 17:54:24 +09001000 log.debug("Router external gateway {} added",
1001 event.externalGateway().getNetworkId());
Ray Milkey08932a72018-02-20 15:34:38 -08001002 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +09001003 case OPENSTACK_ROUTER_GATEWAY_REMOVED:
Jian Li32b03622018-11-06 17:54:24 +09001004 log.debug("Router external gateway {} removed",
1005 event.externalGateway().getNetworkId());
Ray Milkey08932a72018-02-20 15:34:38 -08001006 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +09001007 case OPENSTACK_FLOATING_IP_CREATED:
1008 case OPENSTACK_FLOATING_IP_UPDATED:
1009 case OPENSTACK_FLOATING_IP_REMOVED:
1010 case OPENSTACK_FLOATING_IP_ASSOCIATED:
1011 case OPENSTACK_FLOATING_IP_DISASSOCIATED:
1012 default:
1013 // do nothing for the other events
1014 break;
1015 }
1016 }
1017 }
1018
1019 private class InternalNodeEventListener implements OpenstackNodeListener {
1020
1021 @Override
1022 public boolean isRelevant(OpenstackNodeEvent event) {
1023 // do not allow to proceed without leadership
1024 NodeId leader = leadershipService.getLeader(appId.name());
1025 return Objects.equals(localNodeId, leader);
1026 }
1027
1028 @Override
1029 public void event(OpenstackNodeEvent event) {
1030 OpenstackNode osNode = event.subject();
1031
1032 switch (event.type()) {
Hyunsun Moon0d457362017-06-27 17:19:41 +09001033 case OPENSTACK_NODE_COMPLETE:
1034 case OPENSTACK_NODE_INCOMPLETE:
Daniel Park6ed9cf02018-06-27 19:07:44 +09001035 case OPENSTACK_NODE_UPDATED:
1036 case OPENSTACK_NODE_REMOVED:
Hyunsun Moon44aac662017-02-18 02:07:01 +09001037 eventExecutor.execute(() -> {
Hyunsun Moon0e058f22017-04-19 17:00:52 +09001038 log.info("Reconfigure routers for {}", osNode.hostname());
Hyunsun Moon44aac662017-02-18 02:07:01 +09001039 reconfigureRouters();
1040 });
1041 break;
Hyunsun Moon0d457362017-06-27 17:19:41 +09001042 case OPENSTACK_NODE_CREATED:
Hyunsun Moon44aac662017-02-18 02:07:01 +09001043 default:
1044 break;
1045 }
1046 }
1047
1048 private void reconfigureRouters() {
1049 osRouterService.routers().forEach(osRouter -> {
1050 routerUpdated(osRouter);
1051 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
1052 routerIfaceAdded(osRouter, iface);
1053 });
1054 });
1055 }
1056 }
sangho072c4dd2017-05-17 10:45:21 +09001057
1058 private class InternalInstancePortListener implements InstancePortListener {
1059
1060 @Override
1061 public boolean isRelevant(InstancePortEvent event) {
1062 InstancePort instPort = event.subject();
1063 return mastershipService.isLocalMaster(instPort.deviceId());
1064 }
1065
1066 @Override
1067 public void event(InstancePortEvent event) {
1068 InstancePort instPort = event.subject();
1069 switch (event.type()) {
sangho072c4dd2017-05-17 10:45:21 +09001070 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Liec5c32b2018-07-13 14:28:58 +09001071 case OPENSTACK_INSTANCE_PORT_UPDATED:
1072 log.info("RoutingHandler: Instance port detected MAC:{} IP:{}",
1073 instPort.macAddress(),
1074 instPort.ipAddress());
1075
1076 eventExecutor.execute(() -> instPortDetected(event.subject()));
1077
sangho072c4dd2017-05-17 10:45:21 +09001078 break;
1079 case OPENSTACK_INSTANCE_PORT_VANISHED:
Jian Liec5c32b2018-07-13 14:28:58 +09001080 log.info("RoutingHandler: Instance port vanished MAC:{} IP:{}",
1081 instPort.macAddress(),
1082 instPort.ipAddress());
1083
1084 eventExecutor.execute(() -> instPortRemoved(event.subject()));
1085
1086 break;
1087 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
1088 log.info("RoutingHandler: Migration started for MAC:{} IP:{}",
1089 instPort.macAddress(),
1090 instPort.ipAddress());
1091
1092 eventExecutor.execute(() -> instPortDetected(instPort));
1093
sangho072c4dd2017-05-17 10:45:21 +09001094 break;
Jian Li24ec59f2018-05-23 19:01:25 +09001095 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
Jian Liec5c32b2018-07-13 14:28:58 +09001096 log.info("RoutingHandler: Migration finished for MAC:{} IP:{}",
1097 instPort.macAddress(),
1098 instPort.ipAddress());
Jian Li24ec59f2018-05-23 19:01:25 +09001099 eventExecutor.execute(() -> {
Jian Li24ec59f2018-05-23 19:01:25 +09001100 // TODO: need to reconfigure rules to point to update VM
1101 });
Jian Liec5c32b2018-07-13 14:28:58 +09001102
Jian Li24ec59f2018-05-23 19:01:25 +09001103 break;
sangho072c4dd2017-05-17 10:45:21 +09001104 default:
1105 break;
1106 }
1107 }
1108
1109 private void instPortDetected(InstancePort instPort) {
Jian Li32b03622018-11-06 17:54:24 +09001110 if (osNetworkAdminService.network(instPort.networkId()).getNetworkType() == FLAT) {
daniel park796c2eb2018-03-22 17:01:51 +09001111 return;
1112 }
Daniel Parkc64b4c62018-05-09 18:13:39 +09001113
1114 if (useStatefulSnat) {
1115 osNodeService.completeNodes(GATEWAY)
1116 .forEach(gwNode -> setRulesForSnatIngressRule(
1117 gwNode.intgBridge(),
1118 Long.parseLong(osNetworkAdminService
1119 .network(instPort.networkId()).getProviderSegID()),
1120 IpPrefix.valueOf(instPort.ipAddress(), 32),
1121 instPort.deviceId(), true));
1122 }
sangho072c4dd2017-05-17 10:45:21 +09001123 }
1124
1125 private void instPortRemoved(InstancePort instPort) {
Jian Li32b03622018-11-06 17:54:24 +09001126 if (osNetworkAdminService.network(instPort.networkId()).getNetworkType() == FLAT) {
daniel park796c2eb2018-03-22 17:01:51 +09001127 return;
1128 }
Daniel Parkc64b4c62018-05-09 18:13:39 +09001129
1130 if (useStatefulSnat) {
1131 osNodeService.completeNodes(GATEWAY)
1132 .forEach(gwNode -> setRulesForSnatIngressRule(
1133 gwNode.intgBridge(),
1134 Long.parseLong(osNetworkAdminService
1135 .network(instPort.networkId()).getProviderSegID()),
1136 IpPrefix.valueOf(instPort.ipAddress(), 32),
1137 instPort.deviceId(), false));
1138 }
sangho072c4dd2017-05-17 10:45:21 +09001139 }
1140 }
Hyunsun Moon44aac662017-02-18 02:07:01 +09001141}