blob: e5ecd1c6804652a85bd79f40a9eb683650f09abf [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;
sanghoe765ce22017-06-23 17:54:57 +090029import org.onlab.packet.ICMP;
Hyunsun Moon44aac662017-02-18 02:07:01 +090030import org.onlab.packet.IPv4;
31import org.onlab.packet.IpAddress;
32import org.onlab.packet.IpPrefix;
sangho072c4dd2017-05-17 10:45:21 +090033import org.onlab.packet.MacAddress;
daniel parkee8700b2017-05-11 15:50:03 +090034import org.onlab.packet.VlanId;
sanghoe765ce22017-06-23 17:54:57 +090035import org.onlab.util.Tools;
36import org.onosproject.cfg.ComponentConfigService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090037import org.onosproject.cluster.ClusterService;
38import org.onosproject.cluster.LeadershipService;
39import org.onosproject.cluster.NodeId;
40import org.onosproject.core.ApplicationId;
41import org.onosproject.core.CoreService;
sangho072c4dd2017-05-17 10:45:21 +090042import org.onosproject.mastership.MastershipService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090043import org.onosproject.net.DeviceId;
44import org.onosproject.net.PortNumber;
sangho072c4dd2017-05-17 10:45:21 +090045import org.onosproject.net.device.DeviceService;
46import org.onosproject.net.driver.DriverService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090047import org.onosproject.net.flow.DefaultTrafficSelector;
48import org.onosproject.net.flow.DefaultTrafficTreatment;
49import org.onosproject.net.flow.TrafficSelector;
50import org.onosproject.net.flow.TrafficTreatment;
sangho072c4dd2017-05-17 10:45:21 +090051import org.onosproject.net.flow.instructions.ExtensionTreatment;
Hyunsun Moon44aac662017-02-18 02:07:01 +090052import org.onosproject.openstacknetworking.api.Constants;
daniel park576969a2018-03-09 07:07:41 +090053import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
sangho072c4dd2017-05-17 10:45:21 +090054import org.onosproject.openstacknetworking.api.InstancePort;
55import org.onosproject.openstacknetworking.api.InstancePortEvent;
56import org.onosproject.openstacknetworking.api.InstancePortListener;
57import org.onosproject.openstacknetworking.api.InstancePortService;
sanghodc375372017-06-08 10:41:30 +090058import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
daniel park32b42202018-03-14 16:53:44 +090059import org.onosproject.openstacknetworking.api.OpenstackNetworkAdminService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090060import org.onosproject.openstacknetworking.api.OpenstackRouterEvent;
61import org.onosproject.openstacknetworking.api.OpenstackRouterListener;
62import org.onosproject.openstacknetworking.api.OpenstackRouterService;
Jian Li26949762018-03-30 15:46:37 +090063import org.onosproject.openstacknetworking.util.RulePopulatorUtil;
Hyunsun Moon0d457362017-06-27 17:19:41 +090064import org.onosproject.openstacknode.api.OpenstackNode;
65import org.onosproject.openstacknode.api.OpenstackNode.NetworkMode;
66import org.onosproject.openstacknode.api.OpenstackNodeEvent;
67import org.onosproject.openstacknode.api.OpenstackNodeListener;
68import org.onosproject.openstacknode.api.OpenstackNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090069import org.openstack4j.model.network.ExternalGateway;
70import org.openstack4j.model.network.Network;
daniel parkee8700b2017-05-11 15:50:03 +090071import org.openstack4j.model.network.NetworkType;
Hyunsun Moon44aac662017-02-18 02:07:01 +090072import org.openstack4j.model.network.Router;
73import org.openstack4j.model.network.RouterInterface;
74import org.openstack4j.model.network.Subnet;
sanghoe765ce22017-06-23 17:54:57 +090075import org.osgi.service.component.ComponentContext;
Hyunsun Moon44aac662017-02-18 02:07:01 +090076import org.slf4j.Logger;
77import org.slf4j.LoggerFactory;
78
sanghoe765ce22017-06-23 17:54:57 +090079import java.util.Dictionary;
Hyunsun Moon44aac662017-02-18 02:07:01 +090080import java.util.Objects;
sangho072c4dd2017-05-17 10:45:21 +090081import java.util.Optional;
Hyunsun Moon44aac662017-02-18 02:07:01 +090082import java.util.Set;
83import java.util.concurrent.ExecutorService;
84import java.util.stream.Collectors;
85
86import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
87import static org.onlab.util.Tools.groupedThreads;
sangho072c4dd2017-05-17 10:45:21 +090088import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_EXTERNAL_ROUTER_MAC;
89import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_GATEWAY_MAC;
sangho072c4dd2017-05-17 10:45:21 +090090import static org.onosproject.openstacknetworking.api.Constants.GW_COMMON_TABLE;
91import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
daniel park796c2eb2018-03-22 17:01:51 +090092import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ADMIN_RULE;
sangho072c4dd2017-05-17 10:45:21 +090093import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_EXTERNAL_ROUTING_RULE;
94import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ICMP_RULE;
95import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_INTERNAL_ROUTING_RULE;
sanghoe765ce22017-06-23 17:54:57 +090096import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_STATEFUL_SNAT_RULE;
sangho072c4dd2017-05-17 10:45:21 +090097import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_SWITCHING_RULE;
98import static org.onosproject.openstacknetworking.api.Constants.ROUTING_TABLE;
Jian Li8abf2fe2018-06-12 18:42:30 +090099import static org.onosproject.openstacknetworking.api.Constants.STAT_OUTBOUND_TABLE;
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);
279 setGatewayIcmp(osSubnet, true);
280 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);
303 setGatewayIcmp(osSubnet, false);
304 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)
356 .forEach(port -> setRulesForSnatIngressRule(gwNode.intgBridge(),
sangho072c4dd2017-05-17 10:45:21 +0900357 Long.parseLong(osNet.getProviderSegID()),
358 IpPrefix.valueOf(port.ipAddress(), 32),
359 port.deviceId(),
360 install));
361
362 setOvsNatIngressRule(gwNode.intgBridge(),
363 IpPrefix.valueOf(natAddress, 32),
364 Constants.DEFAULT_EXTERNAL_ROUTER_MAC, install);
365 setOvsNatEgressRule(gwNode.intgBridge(),
366 natAddress, Long.parseLong(osNet.getProviderSegID()),
367 gwNode.patchPortNum(), install);
368 });
sanghoe765ce22017-06-23 17:54:57 +0900369 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900370
sanghoe765ce22017-06-23 17:54:57 +0900371 private void setReactiveSnatRules(RouterInterface routerIface, boolean install) {
Jian Liedc8b762018-03-22 15:42:00 +0900372 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
373 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
sanghoe765ce22017-06-23 17:54:57 +0900374
375 osNodeService.completeNodes(GATEWAY)
376 .forEach(gwNode -> setRulesToController(
377 gwNode.intgBridge(),
378 osNet.getProviderSegID(),
379 IpPrefix.valueOf(osSubnet.getCidr()),
380 osNet.getNetworkType(),
381 install));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900382 }
383
sangho072c4dd2017-05-17 10:45:21 +0900384 private IpAddress getGatewayIpAddress(Router osRouter) {
385
Daniel Park613ac372018-06-28 14:30:11 +0900386 if (osRouter.getExternalGatewayInfo() == null) {
387 return null;
388 }
Jian Liedc8b762018-03-22 15:42:00 +0900389 String extNetId = osNetworkAdminService.network(osRouter.getExternalGatewayInfo().getNetworkId()).getId();
390 Optional<Subnet> extSubnet = osNetworkAdminService.subnets().stream()
sangho072c4dd2017-05-17 10:45:21 +0900391 .filter(subnet -> subnet.getNetworkId().equals(extNetId))
392 .findAny();
393
394 if (!extSubnet.isPresent()) {
395 log.error("Cannot find externel subnet for the router");
396 return null;
397 }
398
399 return IpAddress.valueOf(extSubnet.get().getGateway());
400 }
401
sanghoe765ce22017-06-23 17:54:57 +0900402 private void resetSnatRules() {
403 if (useStatefulSnat) {
404 osRouterService.routerInterfaces().forEach(
405 routerIface -> {
406 setReactiveSnatRules(routerIface, false);
407 setStatefulSnatRules(routerIface, true);
408 }
409 );
410 } else {
411 osRouterService.routerInterfaces().forEach(
412 routerIface -> {
413 setStatefulSnatRules(routerIface, false);
414 setReactiveSnatRules(routerIface, true);
415 }
416 );
417 }
418 }
419
Hyunsun Moon44aac662017-02-18 02:07:01 +0900420 private void setGatewayIcmp(Subnet osSubnet, boolean install) {
daniel parkb5817102018-02-15 00:18:51 +0900421 OpenstackNode sourceNatGateway = osNodeService.completeNodes(GATEWAY).stream().findFirst().orElse(null);
422
423 if (sourceNatGateway == null) {
424 return;
425 }
426
Hyunsun Moon44aac662017-02-18 02:07:01 +0900427 if (Strings.isNullOrEmpty(osSubnet.getGateway())) {
428 // do nothing if no gateway is set
429 return;
430 }
431
432 // take ICMP request to a subnet gateway through gateway node group
Jian Liedc8b762018-03-22 15:42:00 +0900433 Network network = osNetworkAdminService.network(osSubnet.getNetworkId());
daniel parkee8700b2017-05-11 15:50:03 +0900434 switch (network.getNetworkType()) {
435 case VXLAN:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900436 osNodeService.completeNodes(COMPUTE).stream()
437 .filter(cNode -> cNode.dataIp() != null)
438 .forEach(cNode -> setRulesToGatewayWithDstIp(
439 cNode,
daniel parkb5817102018-02-15 00:18:51 +0900440 sourceNatGateway,
daniel parkee8700b2017-05-11 15:50:03 +0900441 network.getProviderSegID(),
442 IpAddress.valueOf(osSubnet.getGateway()),
443 NetworkMode.VXLAN,
444 install));
445 break;
446 case VLAN:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900447 osNodeService.completeNodes(COMPUTE).stream()
448 .filter(cNode -> cNode.vlanPortNum() != null)
449 .forEach(cNode -> setRulesToGatewayWithDstIp(
450 cNode,
daniel parkb5817102018-02-15 00:18:51 +0900451 sourceNatGateway,
daniel parkee8700b2017-05-11 15:50:03 +0900452 network.getProviderSegID(),
453 IpAddress.valueOf(osSubnet.getGateway()),
454 NetworkMode.VLAN,
455 install));
456 break;
457 default:
Jian Li71670d12018-03-02 21:31:07 +0900458 final String error = String.format("%s %s",
459 ERR_UNSUPPORTED_NET_TYPE,
daniel parkee8700b2017-05-11 15:50:03 +0900460 network.getNetworkType().toString());
461 throw new IllegalStateException(error);
462 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900463
464 IpAddress gatewayIp = IpAddress.valueOf(osSubnet.getGateway());
daniel park576969a2018-03-09 07:07:41 +0900465 osNodeService.completeNodes(GATEWAY).forEach(gNode ->
Hyunsun Moon0d457362017-06-27 17:19:41 +0900466 setGatewayIcmpRule(
467 gatewayIp,
468 gNode.intgBridge(),
daniel park576969a2018-03-09 07:07:41 +0900469 install));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900470
471 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
472 log.debug(updateStr + "ICMP to {}", osSubnet.getGateway());
473 }
474
475 private void setInternalRoutes(Router osRouter, Subnet updatedSubnet, boolean install) {
Jian Liedc8b762018-03-22 15:42:00 +0900476 Network updatedNetwork = osNetworkAdminService.network(updatedSubnet.getNetworkId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900477 Set<Subnet> routableSubnets = routableSubnets(osRouter, updatedSubnet.getId());
daniel parkee8700b2017-05-11 15:50:03 +0900478 String updatedSegmendId = getSegmentId(updatedSubnet);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900479
480 // installs rule from/to my subnet intentionally to fix ICMP failure
481 // to my subnet gateway if no external gateway added to the router
Hyunsun Moon0d457362017-06-27 17:19:41 +0900482 osNodeService.completeNodes(COMPUTE).forEach(cNode -> {
483 setInternalRouterRules(
484 cNode.intgBridge(),
485 updatedSegmendId,
486 updatedSegmendId,
487 IpPrefix.valueOf(updatedSubnet.getCidr()),
488 IpPrefix.valueOf(updatedSubnet.getCidr()),
489 updatedNetwork.getNetworkType(),
490 install
491 );
Hyunsun Moon44aac662017-02-18 02:07:01 +0900492
Hyunsun Moon0d457362017-06-27 17:19:41 +0900493 routableSubnets.forEach(subnet -> {
494 setInternalRouterRules(
495 cNode.intgBridge(),
496 updatedSegmendId,
497 getSegmentId(subnet),
498 IpPrefix.valueOf(updatedSubnet.getCidr()),
499 IpPrefix.valueOf(subnet.getCidr()),
500 updatedNetwork.getNetworkType(),
501 install
502 );
503 setInternalRouterRules(
504 cNode.intgBridge(),
505 getSegmentId(subnet),
506 updatedSegmendId,
507 IpPrefix.valueOf(subnet.getCidr()),
508 IpPrefix.valueOf(updatedSubnet.getCidr()),
509 updatedNetwork.getNetworkType(),
510 install
511 );
512 });
513 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900514
daniel parkee8700b2017-05-11 15:50:03 +0900515
Hyunsun Moon44aac662017-02-18 02:07:01 +0900516 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
517 routableSubnets.forEach(subnet -> log.debug(
518 updateStr + "route between subnet:{} and subnet:{}",
519 subnet.getCidr(),
520 updatedSubnet.getCidr()));
521 }
522
523 private Set<Subnet> routableSubnets(Router osRouter, String osSubnetId) {
524 Set<Subnet> osSubnets = osRouterService.routerInterfaces(osRouter.getId())
525 .stream()
526 .filter(iface -> !Objects.equals(iface.getSubnetId(), osSubnetId))
Jian Liedc8b762018-03-22 15:42:00 +0900527 .map(iface -> osNetworkAdminService.subnet(iface.getSubnetId()))
Hyunsun Moon44aac662017-02-18 02:07:01 +0900528 .collect(Collectors.toSet());
529 return ImmutableSet.copyOf(osSubnets);
530 }
531
daniel parkee8700b2017-05-11 15:50:03 +0900532 private String getSegmentId(Subnet osSubnet) {
Jian Liedc8b762018-03-22 15:42:00 +0900533 return osNetworkAdminService.network(osSubnet.getNetworkId()).getProviderSegID();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900534 }
535
536 private void setGatewayIcmpRule(IpAddress gatewayIp, DeviceId deviceId, boolean install) {
537 TrafficSelector selector = DefaultTrafficSelector.builder()
538 .matchEthType(Ethernet.TYPE_IPV4)
539 .matchIPProtocol(IPv4.PROTOCOL_ICMP)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900540 .matchIPDst(gatewayIp.getIp4Address().toIpPrefix())
Hyunsun Moon44aac662017-02-18 02:07:01 +0900541 .build();
542
543 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Li4d5c5c32018-04-02 16:38:18 +0900544 .punt()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900545 .build();
546
sanghodc375372017-06-08 10:41:30 +0900547 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900548 appId,
549 deviceId,
550 selector,
551 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900552 PRIORITY_ICMP_RULE,
sanghodc375372017-06-08 10:41:30 +0900553 Constants.GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900554 install);
555 }
556
daniel parkee8700b2017-05-11 15:50:03 +0900557 private void setInternalRouterRules(DeviceId deviceId, String srcSegmentId, String dstSegmentId,
558 IpPrefix srcSubnet, IpPrefix dstSubnet,
559 NetworkType networkType, boolean install) {
560 TrafficSelector selector;
561 TrafficTreatment treatment;
562 switch (networkType) {
563 case VXLAN:
564 selector = DefaultTrafficSelector.builder()
565 .matchEthType(Ethernet.TYPE_IPV4)
566 .matchTunnelId(Long.parseLong(srcSegmentId))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900567 .matchIPSrc(srcSubnet.getIp4Prefix())
568 .matchIPDst(dstSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900569 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900570
daniel parkee8700b2017-05-11 15:50:03 +0900571 treatment = DefaultTrafficTreatment.builder()
572 .setTunnelId(Long.parseLong(dstSegmentId))
Jian Li8abf2fe2018-06-12 18:42:30 +0900573 .transition(STAT_OUTBOUND_TABLE)
daniel parkee8700b2017-05-11 15:50:03 +0900574 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900575
sanghodc375372017-06-08 10:41:30 +0900576 osFlowRuleService.setRule(
daniel parkee8700b2017-05-11 15:50:03 +0900577 appId,
578 deviceId,
579 selector,
580 treatment,
daniel parkee8700b2017-05-11 15:50:03 +0900581 PRIORITY_INTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900582 ROUTING_TABLE,
daniel parkee8700b2017-05-11 15:50:03 +0900583 install);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900584
daniel parkee8700b2017-05-11 15:50:03 +0900585 selector = DefaultTrafficSelector.builder()
586 .matchEthType(Ethernet.TYPE_IPV4)
587 .matchTunnelId(Long.parseLong(dstSegmentId))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900588 .matchIPSrc(srcSubnet.getIp4Prefix())
589 .matchIPDst(dstSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900590 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900591
daniel parkee8700b2017-05-11 15:50:03 +0900592 treatment = DefaultTrafficTreatment.builder()
593 .setTunnelId(Long.parseLong(dstSegmentId))
Jian Li8abf2fe2018-06-12 18:42:30 +0900594 .transition(STAT_OUTBOUND_TABLE)
daniel parkee8700b2017-05-11 15:50:03 +0900595 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900596
sanghodc375372017-06-08 10:41:30 +0900597 osFlowRuleService.setRule(
daniel parkee8700b2017-05-11 15:50:03 +0900598 appId,
599 deviceId,
600 selector,
601 treatment,
daniel parkee8700b2017-05-11 15:50:03 +0900602 PRIORITY_INTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900603 ROUTING_TABLE,
daniel parkee8700b2017-05-11 15:50:03 +0900604 install);
605 break;
606 case VLAN:
607 selector = DefaultTrafficSelector.builder()
608 .matchEthType(Ethernet.TYPE_IPV4)
609 .matchVlanId(VlanId.vlanId(srcSegmentId))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900610 .matchIPSrc(srcSubnet.getIp4Prefix())
611 .matchIPDst(dstSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900612 .build();
613
614 treatment = DefaultTrafficTreatment.builder()
615 .setVlanId(VlanId.vlanId(dstSegmentId))
Jian Li8abf2fe2018-06-12 18:42:30 +0900616 .transition(STAT_OUTBOUND_TABLE)
daniel parkee8700b2017-05-11 15:50:03 +0900617 .build();
618
sanghodc375372017-06-08 10:41:30 +0900619 osFlowRuleService.setRule(
daniel parkee8700b2017-05-11 15:50:03 +0900620 appId,
621 deviceId,
622 selector,
623 treatment,
daniel parkee8700b2017-05-11 15:50:03 +0900624 PRIORITY_INTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900625 ROUTING_TABLE,
daniel parkee8700b2017-05-11 15:50:03 +0900626 install);
627
628 selector = DefaultTrafficSelector.builder()
629 .matchEthType(Ethernet.TYPE_IPV4)
630 .matchVlanId(VlanId.vlanId(dstSegmentId))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900631 .matchIPSrc(srcSubnet.getIp4Prefix())
632 .matchIPDst(dstSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900633 .build();
634
635 treatment = DefaultTrafficTreatment.builder()
636 .setVlanId(VlanId.vlanId(dstSegmentId))
Jian Li8abf2fe2018-06-12 18:42:30 +0900637 .transition(STAT_OUTBOUND_TABLE)
daniel parkee8700b2017-05-11 15:50:03 +0900638 .build();
639
sanghodc375372017-06-08 10:41:30 +0900640 osFlowRuleService.setRule(
daniel parkee8700b2017-05-11 15:50:03 +0900641 appId,
642 deviceId,
643 selector,
644 treatment,
daniel parkee8700b2017-05-11 15:50:03 +0900645 PRIORITY_INTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900646 ROUTING_TABLE,
daniel parkee8700b2017-05-11 15:50:03 +0900647 install);
648 break;
649 default:
Jian Li71670d12018-03-02 21:31:07 +0900650 final String error = String.format("%s %s",
651 ERR_UNSUPPORTED_NET_TYPE,
daniel parkee8700b2017-05-11 15:50:03 +0900652 networkType.toString());
653 throw new IllegalStateException(error);
654 }
655
Hyunsun Moon44aac662017-02-18 02:07:01 +0900656 }
657
Hyunsun Moon0d457362017-06-27 17:19:41 +0900658 private void setRulesToGateway(OpenstackNode osNode, String segmentId, IpPrefix srcSubnet,
daniel parkee8700b2017-05-11 15:50:03 +0900659 NetworkType networkType, boolean install) {
660 TrafficTreatment treatment;
daniel parkb5817102018-02-15 00:18:51 +0900661 OpenstackNode sourceNatGateway = osNodeService.completeNodes(GATEWAY).stream().findFirst().orElse(null);
662
663 if (sourceNatGateway == null) {
664 return;
665 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900666
daniel parkee8700b2017-05-11 15:50:03 +0900667 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
668 .matchEthType(Ethernet.TYPE_IPV4)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900669 .matchIPSrc(srcSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900670 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
671
672 switch (networkType) {
673 case VXLAN:
674 sBuilder.matchTunnelId(Long.parseLong(segmentId));
daniel parkee8700b2017-05-11 15:50:03 +0900675 break;
676 case VLAN:
677 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
daniel parkee8700b2017-05-11 15:50:03 +0900678 break;
679 default:
Jian Li71670d12018-03-02 21:31:07 +0900680 final String error = String.format("%s %s",
681 ERR_UNSUPPORTED_NET_TYPE,
daniel parkee8700b2017-05-11 15:50:03 +0900682 networkType.toString());
683 throw new IllegalStateException(error);
684 }
685
Daniel Parkc64b4c62018-05-09 18:13:39 +0900686 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
687
688 switch (networkType) {
689 case VXLAN:
690 tBuilder.extension(buildExtension(
691 deviceService,
692 osNode.intgBridge(),
693 sourceNatGateway.dataIp().getIp4Address()),
694 osNode.intgBridge())
695 .setOutput(osNode.tunnelPortNum());
696 break;
697
698 case VLAN:
699 tBuilder.setOutput(osNode.vlanPortNum());
700 break;
701
702 default:
703 break;
704 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900705
sanghodc375372017-06-08 10:41:30 +0900706 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900707 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900708 osNode.intgBridge(),
daniel parkee8700b2017-05-11 15:50:03 +0900709 sBuilder.build(),
Daniel Parkc64b4c62018-05-09 18:13:39 +0900710 tBuilder.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900711 PRIORITY_EXTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900712 ROUTING_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900713 install);
714 }
715
sangho072c4dd2017-05-17 10:45:21 +0900716 private void setRulesForSnatIngressRule(DeviceId deviceId, Long vni, IpPrefix destVmIp,
717 DeviceId dstDeviceId, boolean install) {
718
719 TrafficSelector selector = DefaultTrafficSelector.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900720 .matchEthType(Ethernet.TYPE_IPV4)
sangho072c4dd2017-05-17 10:45:21 +0900721 .matchIPDst(destVmIp)
722 .build();
Hyunsun Moon0d457362017-06-27 17:19:41 +0900723
sangho072c4dd2017-05-17 10:45:21 +0900724 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
725 .setTunnelId(vni)
726 .extension(buildExtension(
727 deviceService,
728 deviceId,
729 osNodeService.node(dstDeviceId).dataIp().getIp4Address()),
730 deviceId)
731 .setOutput(osNodeService.node(deviceId).tunnelPortNum())
732 .build();
daniel parkee8700b2017-05-11 15:50:03 +0900733
sanghodc375372017-06-08 10:41:30 +0900734 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900735 appId,
sangho072c4dd2017-05-17 10:45:21 +0900736 deviceId,
737 selector,
738 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900739 PRIORITY_EXTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900740 Constants.GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900741 install);
742 }
743
daniel parkb5817102018-02-15 00:18:51 +0900744 private void setRulesToGatewayWithDstIp(OpenstackNode osNode, OpenstackNode sourceNatGateway,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900745 String segmentId, IpAddress dstIp,
746 NetworkMode networkMode, boolean install) {
Daniel Parkc64b4c62018-05-09 18:13:39 +0900747 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
748 .matchEthType(Ethernet.TYPE_IPV4)
749 .matchIPDst(dstIp.getIp4Address().toIpPrefix());
750
751 switch (networkMode) {
752 case VXLAN:
753 sBuilder.matchTunnelId(Long.valueOf(segmentId));
754 break;
755
756 case VLAN:
757 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
758 break;
759
760 default:
761 break;
daniel parkee8700b2017-05-11 15:50:03 +0900762 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900763
Daniel Parkc64b4c62018-05-09 18:13:39 +0900764 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
765
766 switch (networkMode) {
767 case VXLAN:
768 tBuilder.extension(buildExtension(
daniel parkb5817102018-02-15 00:18:51 +0900769 deviceService,
770 osNode.intgBridge(),
771 sourceNatGateway.dataIp().getIp4Address()),
772 osNode.intgBridge())
Daniel Parkc64b4c62018-05-09 18:13:39 +0900773 .setOutput(osNode.tunnelPortNum());
774 break;
775
776 case VLAN:
777 tBuilder.setOutput(osNode.vlanPortNum());
778 break;
779
780 default:
781 break;
782 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900783
sanghodc375372017-06-08 10:41:30 +0900784 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900785 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900786 osNode.intgBridge(),
Daniel Parkc64b4c62018-05-09 18:13:39 +0900787 sBuilder.build(),
788 tBuilder.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900789 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900790 ROUTING_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900791 install);
792 }
793
sangho072c4dd2017-05-17 10:45:21 +0900794 private void setOvsNatIngressRule(DeviceId deviceId, IpPrefix cidr, MacAddress dstMac, boolean install) {
795
796 TrafficSelector selector = DefaultTrafficSelector.builder()
797 .matchEthType(Ethernet.TYPE_IPV4)
798 .matchIPDst(cidr)
799 .build();
800
Jian Liedc8b762018-03-22 15:42:00 +0900801 ExtensionTreatment natTreatment = RulePopulatorUtil
802 .niciraConnTrackTreatmentBuilder(driverService, deviceId)
sangho072c4dd2017-05-17 10:45:21 +0900803 .commit(false)
804 .natAction(true)
805 .table((short) 0)
806 .build();
807
808 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
809 .setEthDst(dstMac)
810 .extension(natTreatment, deviceId)
811 .build();
812
813 osFlowRuleService.setRule(
814 appId,
815 deviceId,
816 selector,
817 treatment,
sanghoe765ce22017-06-23 17:54:57 +0900818 PRIORITY_STATEFUL_SNAT_RULE,
sangho072c4dd2017-05-17 10:45:21 +0900819 GW_COMMON_TABLE,
820 install);
821 }
822
823 private void setOvsNatEgressRule(DeviceId deviceId, IpAddress natAddress, long vni, PortNumber output,
824 boolean install) {
825
826 TrafficSelector selector = DefaultTrafficSelector.builder()
827 .matchEthType(Ethernet.TYPE_IPV4)
828 .matchEthDst(DEFAULT_GATEWAY_MAC)
829 .matchTunnelId(vni)
830 .build();
831
Jian Liedc8b762018-03-22 15:42:00 +0900832 ExtensionTreatment natTreatment = RulePopulatorUtil
833 .niciraConnTrackTreatmentBuilder(driverService, deviceId)
sangho072c4dd2017-05-17 10:45:21 +0900834 .commit(true)
835 .natAction(true)
836 .natIp(natAddress)
837 .build();
838
839 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
840 .extension(natTreatment, deviceId)
841 .setEthDst(DEFAULT_EXTERNAL_ROUTER_MAC)
842 .setEthSrc(DEFAULT_GATEWAY_MAC)
843 .setOutput(output)
844 .build();
845
846 osFlowRuleService.setRule(
847 appId,
848 deviceId,
849 selector,
850 treatment,
sanghoe765ce22017-06-23 17:54:57 +0900851 PRIORITY_STATEFUL_SNAT_RULE,
sangho072c4dd2017-05-17 10:45:21 +0900852 GW_COMMON_TABLE,
853 install);
854 }
855
sanghoe765ce22017-06-23 17:54:57 +0900856 private void setRulesToController(DeviceId deviceId, String segmentId, IpPrefix srcSubnet,
857 NetworkType networkType, boolean install) {
858 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
859 .matchEthType(Ethernet.TYPE_IPV4)
Daniel Parkc64b4c62018-05-09 18:13:39 +0900860 .matchIPSrc(srcSubnet)
861 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
862
sanghoe765ce22017-06-23 17:54:57 +0900863
864 switch (networkType) {
865 case VXLAN:
Daniel Parkc64b4c62018-05-09 18:13:39 +0900866 sBuilder.matchTunnelId(Long.parseLong(segmentId));
sanghoe765ce22017-06-23 17:54:57 +0900867 break;
868 case VLAN:
Daniel Parkc64b4c62018-05-09 18:13:39 +0900869 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
sanghoe765ce22017-06-23 17:54:57 +0900870 break;
871 default:
Jian Li71670d12018-03-02 21:31:07 +0900872 final String error = String.format("%s %s",
873 ERR_UNSUPPORTED_NET_TYPE,
sanghoe765ce22017-06-23 17:54:57 +0900874 networkType.toString());
875 throw new IllegalStateException(error);
876 }
877
Daniel Parkc64b4c62018-05-09 18:13:39 +0900878 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
sanghoe765ce22017-06-23 17:54:57 +0900879
880 if (networkType.equals(NetworkType.VLAN)) {
881 tBuilder.popVlan();
882 }
883
Jian Li4d5c5c32018-04-02 16:38:18 +0900884 tBuilder.punt();
sanghoe765ce22017-06-23 17:54:57 +0900885
886 osFlowRuleService.setRule(
887 appId,
888 deviceId,
889 sBuilder.build(),
890 tBuilder.build(),
891 PRIORITY_EXTERNAL_ROUTING_RULE,
892 GW_COMMON_TABLE,
893 install);
894
895
896 // Sends ICMP response to controller for SNATing ingress traffic
897 TrafficSelector selector = DefaultTrafficSelector.builder()
898 .matchEthType(Ethernet.TYPE_IPV4)
899 .matchIPProtocol(IPv4.PROTOCOL_ICMP)
900 .matchIcmpType(ICMP.TYPE_ECHO_REPLY)
901 .build();
902
903 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Li4d5c5c32018-04-02 16:38:18 +0900904 .punt()
sanghoe765ce22017-06-23 17:54:57 +0900905 .build();
906
907 osFlowRuleService.setRule(
908 appId,
909 deviceId,
910 selector,
911 treatment,
912 PRIORITY_INTERNAL_ROUTING_RULE,
913 GW_COMMON_TABLE,
914 install);
915 }
sangho072c4dd2017-05-17 10:45:21 +0900916
Frank Wang245a6822017-06-14 09:51:35 +0800917 private void setRouterAdminRules(String segmentId, NetworkType networkType, boolean install) {
918 TrafficTreatment treatment;
919 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
920 .matchEthType(Ethernet.TYPE_IPV4);
921
922 switch (networkType) {
923 case VXLAN:
924 sBuilder.matchTunnelId(Long.parseLong(segmentId));
925 break;
926 case VLAN:
927 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
928 break;
929 default:
Jian Li71670d12018-03-02 21:31:07 +0900930 final String error = String.format("%s %s",
931 ERR_UNSUPPORTED_NET_TYPE,
Frank Wang245a6822017-06-14 09:51:35 +0800932 networkType.toString());
933 throw new IllegalStateException(error);
934 }
935
936 treatment = DefaultTrafficTreatment.builder()
937 .drop()
938 .build();
939
940 osNodeService.completeNodes().stream()
941 .filter(osNode -> osNode.type() == COMPUTE)
942 .forEach(osNode -> {
943 osFlowRuleService.setRule(
944 appId,
945 osNode.intgBridge(),
946 sBuilder.build(),
947 treatment,
948 PRIORITY_ADMIN_RULE,
949 ROUTING_TABLE,
950 install);
951 });
952 }
953
Hyunsun Moon44aac662017-02-18 02:07:01 +0900954 private class InternalRouterEventListener implements OpenstackRouterListener {
955
956 @Override
957 public boolean isRelevant(OpenstackRouterEvent event) {
958 // do not allow to proceed without leadership
959 NodeId leader = leadershipService.getLeader(appId.name());
960 return Objects.equals(localNodeId, leader);
961 }
962
963 // FIXME only one leader in the cluster should process
964 @Override
965 public void event(OpenstackRouterEvent event) {
966 switch (event.type()) {
967 case OPENSTACK_ROUTER_CREATED:
968 log.debug("Router(name:{}, ID:{}) is created",
969 event.subject().getName(),
970 event.subject().getId());
971 eventExecutor.execute(() -> routerUpdated(event.subject()));
972 break;
973 case OPENSTACK_ROUTER_UPDATED:
974 log.debug("Router(name:{}, ID:{}) is updated",
975 event.subject().getName(),
976 event.subject().getId());
977 eventExecutor.execute(() -> routerUpdated(event.subject()));
978 break;
979 case OPENSTACK_ROUTER_REMOVED:
980 log.debug("Router(name:{}, ID:{}) is removed",
981 event.subject().getName(),
982 event.subject().getId());
Frank Wang245a6822017-06-14 09:51:35 +0800983 eventExecutor.execute(() -> routerRemove(event.subject()));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900984 break;
985 case OPENSTACK_ROUTER_INTERFACE_ADDED:
986 log.debug("Router interface {} added to router {}",
987 event.routerIface().getPortId(),
988 event.routerIface().getId());
989 eventExecutor.execute(() -> routerIfaceAdded(
990 event.subject(),
991 event.routerIface()));
992 break;
993 case OPENSTACK_ROUTER_INTERFACE_UPDATED:
994 log.debug("Router interface {} on {} updated",
995 event.routerIface().getPortId(),
996 event.routerIface().getId());
997 break;
998 case OPENSTACK_ROUTER_INTERFACE_REMOVED:
999 log.debug("Router interface {} removed from router {}",
1000 event.routerIface().getPortId(),
1001 event.routerIface().getId());
1002 eventExecutor.execute(() -> routerIfaceRemoved(
1003 event.subject(),
1004 event.routerIface()));
1005 break;
1006 case OPENSTACK_ROUTER_GATEWAY_ADDED:
daniel parkb5817102018-02-15 00:18:51 +09001007 log.debug("Router external gateway {} added", event.externalGateway().getNetworkId());
Ray Milkey08932a72018-02-20 15:34:38 -08001008 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +09001009 case OPENSTACK_ROUTER_GATEWAY_REMOVED:
daniel parkb5817102018-02-15 00:18:51 +09001010 log.debug("Router external gateway {} removed", event.externalGateway().getNetworkId());
Ray Milkey08932a72018-02-20 15:34:38 -08001011 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +09001012 case OPENSTACK_FLOATING_IP_CREATED:
1013 case OPENSTACK_FLOATING_IP_UPDATED:
1014 case OPENSTACK_FLOATING_IP_REMOVED:
1015 case OPENSTACK_FLOATING_IP_ASSOCIATED:
1016 case OPENSTACK_FLOATING_IP_DISASSOCIATED:
1017 default:
1018 // do nothing for the other events
1019 break;
1020 }
1021 }
1022 }
1023
1024 private class InternalNodeEventListener implements OpenstackNodeListener {
1025
1026 @Override
1027 public boolean isRelevant(OpenstackNodeEvent event) {
1028 // do not allow to proceed without leadership
1029 NodeId leader = leadershipService.getLeader(appId.name());
1030 return Objects.equals(localNodeId, leader);
1031 }
1032
1033 @Override
1034 public void event(OpenstackNodeEvent event) {
1035 OpenstackNode osNode = event.subject();
1036
1037 switch (event.type()) {
Hyunsun Moon0d457362017-06-27 17:19:41 +09001038 case OPENSTACK_NODE_COMPLETE:
1039 case OPENSTACK_NODE_INCOMPLETE:
Daniel Park6ed9cf02018-06-27 19:07:44 +09001040 case OPENSTACK_NODE_UPDATED:
1041 case OPENSTACK_NODE_REMOVED:
Hyunsun Moon44aac662017-02-18 02:07:01 +09001042 eventExecutor.execute(() -> {
Hyunsun Moon0e058f22017-04-19 17:00:52 +09001043 log.info("Reconfigure routers for {}", osNode.hostname());
Hyunsun Moon44aac662017-02-18 02:07:01 +09001044 reconfigureRouters();
1045 });
1046 break;
Hyunsun Moon0d457362017-06-27 17:19:41 +09001047 case OPENSTACK_NODE_CREATED:
Hyunsun Moon44aac662017-02-18 02:07:01 +09001048 default:
1049 break;
1050 }
1051 }
1052
1053 private void reconfigureRouters() {
1054 osRouterService.routers().forEach(osRouter -> {
1055 routerUpdated(osRouter);
1056 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
1057 routerIfaceAdded(osRouter, iface);
1058 });
1059 });
1060 }
1061 }
sangho072c4dd2017-05-17 10:45:21 +09001062
1063 private class InternalInstancePortListener implements InstancePortListener {
1064
1065 @Override
1066 public boolean isRelevant(InstancePortEvent event) {
1067 InstancePort instPort = event.subject();
1068 return mastershipService.isLocalMaster(instPort.deviceId());
1069 }
1070
1071 @Override
1072 public void event(InstancePortEvent event) {
1073 InstancePort instPort = event.subject();
1074 switch (event.type()) {
sangho072c4dd2017-05-17 10:45:21 +09001075 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Liec5c32b2018-07-13 14:28:58 +09001076 case OPENSTACK_INSTANCE_PORT_UPDATED:
1077 log.info("RoutingHandler: Instance port detected MAC:{} IP:{}",
1078 instPort.macAddress(),
1079 instPort.ipAddress());
1080
1081 eventExecutor.execute(() -> instPortDetected(event.subject()));
1082
sangho072c4dd2017-05-17 10:45:21 +09001083 break;
1084 case OPENSTACK_INSTANCE_PORT_VANISHED:
Jian Liec5c32b2018-07-13 14:28:58 +09001085 log.info("RoutingHandler: Instance port vanished MAC:{} IP:{}",
1086 instPort.macAddress(),
1087 instPort.ipAddress());
1088
1089 eventExecutor.execute(() -> instPortRemoved(event.subject()));
1090
1091 break;
1092 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
1093 log.info("RoutingHandler: Migration started for MAC:{} IP:{}",
1094 instPort.macAddress(),
1095 instPort.ipAddress());
1096
1097 eventExecutor.execute(() -> instPortDetected(instPort));
1098
sangho072c4dd2017-05-17 10:45:21 +09001099 break;
Jian Li24ec59f2018-05-23 19:01:25 +09001100 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
Jian Liec5c32b2018-07-13 14:28:58 +09001101 log.info("RoutingHandler: Migration finished for MAC:{} IP:{}",
1102 instPort.macAddress(),
1103 instPort.ipAddress());
Jian Li24ec59f2018-05-23 19:01:25 +09001104 eventExecutor.execute(() -> {
Jian Li24ec59f2018-05-23 19:01:25 +09001105 // TODO: need to reconfigure rules to point to update VM
1106 });
Jian Liec5c32b2018-07-13 14:28:58 +09001107
Jian Li24ec59f2018-05-23 19:01:25 +09001108 break;
sangho072c4dd2017-05-17 10:45:21 +09001109 default:
1110 break;
1111 }
1112 }
1113
1114 private void instPortDetected(InstancePort instPort) {
daniel park796c2eb2018-03-22 17:01:51 +09001115 if (osNetworkAdminService.network(instPort.networkId()).getNetworkType() == NetworkType.FLAT) {
1116 return;
1117 }
Daniel Parkc64b4c62018-05-09 18:13:39 +09001118
1119 if (useStatefulSnat) {
1120 osNodeService.completeNodes(GATEWAY)
1121 .forEach(gwNode -> setRulesForSnatIngressRule(
1122 gwNode.intgBridge(),
1123 Long.parseLong(osNetworkAdminService
1124 .network(instPort.networkId()).getProviderSegID()),
1125 IpPrefix.valueOf(instPort.ipAddress(), 32),
1126 instPort.deviceId(), true));
1127 }
sangho072c4dd2017-05-17 10:45:21 +09001128 }
1129
1130 private void instPortRemoved(InstancePort instPort) {
daniel park796c2eb2018-03-22 17:01:51 +09001131 if (osNetworkAdminService.network(instPort.networkId()).getNetworkType() == NetworkType.FLAT) {
1132 return;
1133 }
Daniel Parkc64b4c62018-05-09 18:13:39 +09001134
1135 if (useStatefulSnat) {
1136 osNodeService.completeNodes(GATEWAY)
1137 .forEach(gwNode -> setRulesForSnatIngressRule(
1138 gwNode.intgBridge(),
1139 Long.parseLong(osNetworkAdminService
1140 .network(instPort.networkId()).getProviderSegID()),
1141 IpPrefix.valueOf(instPort.ipAddress(), 32),
1142 instPort.deviceId(), false));
1143 }
sangho072c4dd2017-05-17 10:45:21 +09001144 }
1145 }
Hyunsun Moon44aac662017-02-18 02:07:01 +09001146}