blob: e174eef66f5d22ac7867e7ad1ff1f52c0193fe43 [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;
20import org.apache.felix.scr.annotations.Activate;
21import org.apache.felix.scr.annotations.Component;
22import org.apache.felix.scr.annotations.Deactivate;
sanghoe765ce22017-06-23 17:54:57 +090023import org.apache.felix.scr.annotations.Modified;
24import org.apache.felix.scr.annotations.Property;
Hyunsun Moon44aac662017-02-18 02:07:01 +090025import org.apache.felix.scr.annotations.Reference;
26import org.apache.felix.scr.annotations.ReferenceCardinality;
27import org.onlab.packet.Ethernet;
sanghoe765ce22017-06-23 17:54:57 +090028import org.onlab.packet.ICMP;
Hyunsun Moon44aac662017-02-18 02:07:01 +090029import 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 Li26949762018-03-30 15:46:37 +090099import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900100import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
101import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900102
103/**
104 * Handles OpenStack router events.
105 */
106@Component(immediate = true)
107public class OpenstackRoutingHandler {
108
109 private final Logger log = LoggerFactory.getLogger(getClass());
110
111 private static final String MSG_ENABLED = "Enabled ";
112 private static final String MSG_DISABLED = "Disabled ";
daniel parkee8700b2017-05-11 15:50:03 +0900113 private static final String ERR_UNSUPPORTED_NET_TYPE = "Unsupported network type";
sanghoe765ce22017-06-23 17:54:57 +0900114 private static final boolean USE_STATEFUL_SNAT = false;
115
116 @Property(name = "useStatefulSnat", boolValue = USE_STATEFUL_SNAT,
117 label = "Use Stateful SNAT for source NATing")
118 private boolean useStatefulSnat = USE_STATEFUL_SNAT;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900119
120 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
121 protected CoreService coreService;
122
123 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
124 protected LeadershipService leadershipService;
125
126 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
127 protected ClusterService clusterService;
128
129 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900130 protected OpenstackNodeService osNodeService;
131
132 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
daniel park32b42202018-03-14 16:53:44 +0900133 protected OpenstackNetworkAdminService osNetworkAdminService;
134
135 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900136 protected OpenstackRouterService osRouterService;
137
daniel parkee8700b2017-05-11 15:50:03 +0900138 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho072c4dd2017-05-17 10:45:21 +0900139 protected InstancePortService instancePortService;
140
141 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
142 protected DeviceService deviceService;
143
144 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sanghodc375372017-06-08 10:41:30 +0900145 protected OpenstackFlowRuleService osFlowRuleService;
146
sangho072c4dd2017-05-17 10:45:21 +0900147 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
148 protected MastershipService mastershipService;
149
150 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
151 protected DriverService driverService;
152
sanghoe765ce22017-06-23 17:54:57 +0900153 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
154 protected ComponentConfigService configService;
155
Hyunsun Moon44aac662017-02-18 02:07:01 +0900156 private final ExecutorService eventExecutor = newSingleThreadScheduledExecutor(
157 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
158 private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
159 private final OpenstackRouterListener osRouterListener = new InternalRouterEventListener();
sangho072c4dd2017-05-17 10:45:21 +0900160 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900161
162 private ApplicationId appId;
163 private NodeId localNodeId;
164
165 @Activate
166 protected void activate() {
167 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
168 localNodeId = clusterService.getLocalNode().id();
169 leadershipService.runForLeadership(appId.name());
170 osNodeService.addListener(osNodeListener);
171 osRouterService.addListener(osRouterListener);
sangho072c4dd2017-05-17 10:45:21 +0900172 instancePortService.addListener(instancePortListener);
sanghoe765ce22017-06-23 17:54:57 +0900173 configService.registerProperties(getClass());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900174
175 log.info("Started");
176 }
177
178 @Deactivate
179 protected void deactivate() {
180 osRouterService.removeListener(osRouterListener);
181 osNodeService.removeListener(osNodeListener);
sangho072c4dd2017-05-17 10:45:21 +0900182 instancePortService.removeListener(instancePortListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900183 leadershipService.withdraw(appId.name());
sanghoe765ce22017-06-23 17:54:57 +0900184 configService.unregisterProperties(getClass(), false);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900185 eventExecutor.shutdown();
186
187 log.info("Stopped");
188 }
189
sanghoe765ce22017-06-23 17:54:57 +0900190 @Modified
191 protected void modified(ComponentContext context) {
192 Dictionary<?, ?> properties = context.getProperties();
193 Boolean flag;
194
195 flag = Tools.isPropertyEnabled(properties, "useStatefulSnat");
196 if (flag == null) {
197 log.info("useStatefulSnat is not configured, " +
198 "using current value of {}", useStatefulSnat);
199 } else {
200 useStatefulSnat = flag;
201 log.info("Configured. useStatefulSnat is {}",
202 useStatefulSnat ? "enabled" : "disabled");
203 }
204
205 resetSnatRules();
206 }
207
Hyunsun Moon44aac662017-02-18 02:07:01 +0900208 private void routerUpdated(Router osRouter) {
209 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
Frank Wang245a6822017-06-14 09:51:35 +0800210 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
Jian Liedc8b762018-03-22 15:42:00 +0900211 Network network = osNetworkAdminService.network(osNetworkAdminService.subnet(iface.getSubnetId())
Frank Wang245a6822017-06-14 09:51:35 +0800212 .getNetworkId());
213 setRouterAdminRules(network.getProviderSegID(), network.getNetworkType(), !osRouter.isAdminStateUp());
214 });
215
Jian Liedc8b762018-03-22 15:42:00 +0900216 ExternalPeerRouter externalPeerRouter = osNetworkAdminService.externalPeerRouter(exGateway);
daniel park576969a2018-03-09 07:07:41 +0900217 VlanId vlanId = externalPeerRouter == null ? VlanId.NONE : externalPeerRouter.externalPeerRouterVlanId();
218
Hyunsun Moon44aac662017-02-18 02:07:01 +0900219 if (exGateway == null) {
daniel park32b42202018-03-14 16:53:44 +0900220 osNetworkAdminService.deleteExternalPeerRouter(exGateway);
daniel park576969a2018-03-09 07:07:41 +0900221 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> setSourceNat(iface, false));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900222 } else {
daniel park32b42202018-03-14 16:53:44 +0900223 osNetworkAdminService.deriveExternalPeerRouterMac(exGateway, osRouter, vlanId);
daniel park576969a2018-03-09 07:07:41 +0900224 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface ->
225 setSourceNat(iface, exGateway.isEnableSnat()));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900226 }
227 }
228
Frank Wang245a6822017-06-14 09:51:35 +0800229 private void routerRemove(Router osRouter) {
230 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
Jian Liedc8b762018-03-22 15:42:00 +0900231 Network network = osNetworkAdminService.network(osNetworkAdminService.subnet(iface.getSubnetId())
Frank Wang245a6822017-06-14 09:51:35 +0800232 .getNetworkId());
233 setRouterAdminRules(network.getProviderSegID(), network.getNetworkType(), false);
234 });
235 }
236
Hyunsun Moon44aac662017-02-18 02:07:01 +0900237 private void routerIfaceAdded(Router osRouter, RouterInterface osRouterIface) {
Jian Liedc8b762018-03-22 15:42:00 +0900238 Subnet osSubnet = osNetworkAdminService.subnet(osRouterIface.getSubnetId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900239 if (osSubnet == null) {
240 final String error = String.format(
Jian Li71670d12018-03-02 21:31:07 +0900241 "Failed to set flows for router %s: subnet %s does not exist",
Hyunsun Moon44aac662017-02-18 02:07:01 +0900242 osRouterIface.getId(),
243 osRouterIface.getSubnetId());
244 throw new IllegalStateException(error);
245 }
Frank Wang245a6822017-06-14 09:51:35 +0800246
247 if (!osRouter.isAdminStateUp()) {
Jian Liedc8b762018-03-22 15:42:00 +0900248 Network network = osNetworkAdminService.network(osSubnet.getNetworkId());
Frank Wang245a6822017-06-14 09:51:35 +0800249 setRouterAdminRules(network.getProviderSegID(), network.getNetworkType(), true);
250 }
251
Hyunsun Moon44aac662017-02-18 02:07:01 +0900252 setInternalRoutes(osRouter, osSubnet, true);
253 setGatewayIcmp(osSubnet, true);
254 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
255 if (exGateway != null && exGateway.isEnableSnat()) {
daniel park576969a2018-03-09 07:07:41 +0900256 setSourceNat(osRouterIface, true);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900257 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900258 log.info("Connected subnet({}) to {}", osSubnet.getCidr(), osRouter.getName());
259 }
260
261 private void routerIfaceRemoved(Router osRouter, RouterInterface osRouterIface) {
Jian Liedc8b762018-03-22 15:42:00 +0900262 Subnet osSubnet = osNetworkAdminService.subnet(osRouterIface.getSubnetId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900263 if (osSubnet == null) {
264 final String error = String.format(
Jian Li71670d12018-03-02 21:31:07 +0900265 "Failed to set flows for router %s: subnet %s does not exist",
Hyunsun Moon44aac662017-02-18 02:07:01 +0900266 osRouterIface.getId(),
267 osRouterIface.getSubnetId());
268 throw new IllegalStateException(error);
269 }
270
Frank Wang245a6822017-06-14 09:51:35 +0800271 if (!osRouter.isAdminStateUp()) {
Jian Liedc8b762018-03-22 15:42:00 +0900272 Network network = osNetworkAdminService.network(osSubnet.getNetworkId());
Frank Wang245a6822017-06-14 09:51:35 +0800273 setRouterAdminRules(network.getProviderSegID(), network.getNetworkType(), false);
274 }
275
Hyunsun Moon44aac662017-02-18 02:07:01 +0900276 setInternalRoutes(osRouter, osSubnet, false);
277 setGatewayIcmp(osSubnet, false);
278 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
279 if (exGateway != null && exGateway.isEnableSnat()) {
daniel park576969a2018-03-09 07:07:41 +0900280 setSourceNat(osRouterIface, false);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900281 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900282 log.info("Disconnected subnet({}) from {}", osSubnet.getCidr(), osRouter.getName());
283 }
284
daniel park576969a2018-03-09 07:07:41 +0900285 private void setSourceNat(RouterInterface routerIface, boolean install) {
Jian Liedc8b762018-03-22 15:42:00 +0900286 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
287 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900288
Hyunsun Moon0d457362017-06-27 17:19:41 +0900289 osNodeService.completeNodes(COMPUTE).forEach(cNode -> {
290 setRulesToGateway(cNode, osNet.getProviderSegID(),
291 IpPrefix.valueOf(osSubnet.getCidr()), osNet.getNetworkType(),
292 install);
293 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900294
sanghoe765ce22017-06-23 17:54:57 +0900295 if (useStatefulSnat) {
296 setStatefulSnatRules(routerIface, install);
297 } else {
298 setReactiveSnatRules(routerIface, install);
299 }
300
301 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
302 log.info(updateStr + "external access for subnet({})", osSubnet.getCidr());
303 }
304
305 private void setStatefulSnatRules(RouterInterface routerIface, boolean install) {
Jian Liedc8b762018-03-22 15:42:00 +0900306 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
307 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
sanghoe765ce22017-06-23 17:54:57 +0900308
daniel park796c2eb2018-03-22 17:01:51 +0900309 if (osNet.getNetworkType() == NetworkType.FLAT) {
310 return;
311 }
312
sanghoe765ce22017-06-23 17:54:57 +0900313 Optional<Router> osRouter = osRouterService.routers().stream()
314 .filter(router -> osRouterService.routerInterfaces(routerIface.getId()) != null)
315 .findAny();
316
317 if (!osRouter.isPresent()) {
318 log.error("Cannot find a router for router interface {} ", routerIface);
319 return;
320 }
321 IpAddress natAddress = getGatewayIpAddress(osRouter.get());
sangho072c4dd2017-05-17 10:45:21 +0900322 if (natAddress == null) {
323 return;
324 }
Jian Liedc8b762018-03-22 15:42:00 +0900325 String netId = osNetworkAdminService.subnet(routerIface.getSubnetId()).getNetworkId();
sangho072c4dd2017-05-17 10:45:21 +0900326
327 osNodeService.completeNodes(OpenstackNode.NodeType.GATEWAY)
328 .forEach(gwNode -> {
daniel park576969a2018-03-09 07:07:41 +0900329 instancePortService.instancePorts(netId)
330 .forEach(port -> setRulesForSnatIngressRule(gwNode.intgBridge(),
sangho072c4dd2017-05-17 10:45:21 +0900331 Long.parseLong(osNet.getProviderSegID()),
332 IpPrefix.valueOf(port.ipAddress(), 32),
333 port.deviceId(),
334 install));
335
336 setOvsNatIngressRule(gwNode.intgBridge(),
337 IpPrefix.valueOf(natAddress, 32),
338 Constants.DEFAULT_EXTERNAL_ROUTER_MAC, install);
339 setOvsNatEgressRule(gwNode.intgBridge(),
340 natAddress, Long.parseLong(osNet.getProviderSegID()),
341 gwNode.patchPortNum(), install);
342 });
sanghoe765ce22017-06-23 17:54:57 +0900343 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900344
sanghoe765ce22017-06-23 17:54:57 +0900345 private void setReactiveSnatRules(RouterInterface routerIface, boolean install) {
Jian Liedc8b762018-03-22 15:42:00 +0900346 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
347 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
sanghoe765ce22017-06-23 17:54:57 +0900348
349 osNodeService.completeNodes(GATEWAY)
350 .forEach(gwNode -> setRulesToController(
351 gwNode.intgBridge(),
352 osNet.getProviderSegID(),
353 IpPrefix.valueOf(osSubnet.getCidr()),
354 osNet.getNetworkType(),
355 install));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900356 }
357
sangho072c4dd2017-05-17 10:45:21 +0900358 private IpAddress getGatewayIpAddress(Router osRouter) {
359
Jian Liedc8b762018-03-22 15:42:00 +0900360 String extNetId = osNetworkAdminService.network(osRouter.getExternalGatewayInfo().getNetworkId()).getId();
361 Optional<Subnet> extSubnet = osNetworkAdminService.subnets().stream()
sangho072c4dd2017-05-17 10:45:21 +0900362 .filter(subnet -> subnet.getNetworkId().equals(extNetId))
363 .findAny();
364
365 if (!extSubnet.isPresent()) {
366 log.error("Cannot find externel subnet for the router");
367 return null;
368 }
369
370 return IpAddress.valueOf(extSubnet.get().getGateway());
371 }
372
sanghoe765ce22017-06-23 17:54:57 +0900373 private void resetSnatRules() {
374 if (useStatefulSnat) {
375 osRouterService.routerInterfaces().forEach(
376 routerIface -> {
377 setReactiveSnatRules(routerIface, false);
378 setStatefulSnatRules(routerIface, true);
379 }
380 );
381 } else {
382 osRouterService.routerInterfaces().forEach(
383 routerIface -> {
384 setStatefulSnatRules(routerIface, false);
385 setReactiveSnatRules(routerIface, true);
386 }
387 );
388 }
389 }
390
Hyunsun Moon44aac662017-02-18 02:07:01 +0900391 private void setGatewayIcmp(Subnet osSubnet, boolean install) {
daniel parkb5817102018-02-15 00:18:51 +0900392 OpenstackNode sourceNatGateway = osNodeService.completeNodes(GATEWAY).stream().findFirst().orElse(null);
393
394 if (sourceNatGateway == null) {
395 return;
396 }
397
Hyunsun Moon44aac662017-02-18 02:07:01 +0900398 if (Strings.isNullOrEmpty(osSubnet.getGateway())) {
399 // do nothing if no gateway is set
400 return;
401 }
402
403 // take ICMP request to a subnet gateway through gateway node group
Jian Liedc8b762018-03-22 15:42:00 +0900404 Network network = osNetworkAdminService.network(osSubnet.getNetworkId());
daniel parkee8700b2017-05-11 15:50:03 +0900405 switch (network.getNetworkType()) {
406 case VXLAN:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900407 osNodeService.completeNodes(COMPUTE).stream()
408 .filter(cNode -> cNode.dataIp() != null)
409 .forEach(cNode -> setRulesToGatewayWithDstIp(
410 cNode,
daniel parkb5817102018-02-15 00:18:51 +0900411 sourceNatGateway,
daniel parkee8700b2017-05-11 15:50:03 +0900412 network.getProviderSegID(),
413 IpAddress.valueOf(osSubnet.getGateway()),
414 NetworkMode.VXLAN,
415 install));
416 break;
417 case VLAN:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900418 osNodeService.completeNodes(COMPUTE).stream()
419 .filter(cNode -> cNode.vlanPortNum() != null)
420 .forEach(cNode -> setRulesToGatewayWithDstIp(
421 cNode,
daniel parkb5817102018-02-15 00:18:51 +0900422 sourceNatGateway,
daniel parkee8700b2017-05-11 15:50:03 +0900423 network.getProviderSegID(),
424 IpAddress.valueOf(osSubnet.getGateway()),
425 NetworkMode.VLAN,
426 install));
427 break;
428 default:
Jian Li71670d12018-03-02 21:31:07 +0900429 final String error = String.format("%s %s",
430 ERR_UNSUPPORTED_NET_TYPE,
daniel parkee8700b2017-05-11 15:50:03 +0900431 network.getNetworkType().toString());
432 throw new IllegalStateException(error);
433 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900434
435 IpAddress gatewayIp = IpAddress.valueOf(osSubnet.getGateway());
daniel park576969a2018-03-09 07:07:41 +0900436 osNodeService.completeNodes(GATEWAY).forEach(gNode ->
Hyunsun Moon0d457362017-06-27 17:19:41 +0900437 setGatewayIcmpRule(
438 gatewayIp,
439 gNode.intgBridge(),
daniel park576969a2018-03-09 07:07:41 +0900440 install));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900441
442 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
443 log.debug(updateStr + "ICMP to {}", osSubnet.getGateway());
444 }
445
446 private void setInternalRoutes(Router osRouter, Subnet updatedSubnet, boolean install) {
Jian Liedc8b762018-03-22 15:42:00 +0900447 Network updatedNetwork = osNetworkAdminService.network(updatedSubnet.getNetworkId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900448 Set<Subnet> routableSubnets = routableSubnets(osRouter, updatedSubnet.getId());
daniel parkee8700b2017-05-11 15:50:03 +0900449 String updatedSegmendId = getSegmentId(updatedSubnet);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900450
451 // installs rule from/to my subnet intentionally to fix ICMP failure
452 // to my subnet gateway if no external gateway added to the router
Hyunsun Moon0d457362017-06-27 17:19:41 +0900453 osNodeService.completeNodes(COMPUTE).forEach(cNode -> {
454 setInternalRouterRules(
455 cNode.intgBridge(),
456 updatedSegmendId,
457 updatedSegmendId,
458 IpPrefix.valueOf(updatedSubnet.getCidr()),
459 IpPrefix.valueOf(updatedSubnet.getCidr()),
460 updatedNetwork.getNetworkType(),
461 install
462 );
Hyunsun Moon44aac662017-02-18 02:07:01 +0900463
Hyunsun Moon0d457362017-06-27 17:19:41 +0900464 routableSubnets.forEach(subnet -> {
465 setInternalRouterRules(
466 cNode.intgBridge(),
467 updatedSegmendId,
468 getSegmentId(subnet),
469 IpPrefix.valueOf(updatedSubnet.getCidr()),
470 IpPrefix.valueOf(subnet.getCidr()),
471 updatedNetwork.getNetworkType(),
472 install
473 );
474 setInternalRouterRules(
475 cNode.intgBridge(),
476 getSegmentId(subnet),
477 updatedSegmendId,
478 IpPrefix.valueOf(subnet.getCidr()),
479 IpPrefix.valueOf(updatedSubnet.getCidr()),
480 updatedNetwork.getNetworkType(),
481 install
482 );
483 });
484 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900485
daniel parkee8700b2017-05-11 15:50:03 +0900486
Hyunsun Moon44aac662017-02-18 02:07:01 +0900487 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
488 routableSubnets.forEach(subnet -> log.debug(
489 updateStr + "route between subnet:{} and subnet:{}",
490 subnet.getCidr(),
491 updatedSubnet.getCidr()));
492 }
493
494 private Set<Subnet> routableSubnets(Router osRouter, String osSubnetId) {
495 Set<Subnet> osSubnets = osRouterService.routerInterfaces(osRouter.getId())
496 .stream()
497 .filter(iface -> !Objects.equals(iface.getSubnetId(), osSubnetId))
Jian Liedc8b762018-03-22 15:42:00 +0900498 .map(iface -> osNetworkAdminService.subnet(iface.getSubnetId()))
Hyunsun Moon44aac662017-02-18 02:07:01 +0900499 .collect(Collectors.toSet());
500 return ImmutableSet.copyOf(osSubnets);
501 }
502
daniel parkee8700b2017-05-11 15:50:03 +0900503 private String getSegmentId(Subnet osSubnet) {
Jian Liedc8b762018-03-22 15:42:00 +0900504 return osNetworkAdminService.network(osSubnet.getNetworkId()).getProviderSegID();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900505 }
506
507 private void setGatewayIcmpRule(IpAddress gatewayIp, DeviceId deviceId, boolean install) {
508 TrafficSelector selector = DefaultTrafficSelector.builder()
509 .matchEthType(Ethernet.TYPE_IPV4)
510 .matchIPProtocol(IPv4.PROTOCOL_ICMP)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900511 .matchIPDst(gatewayIp.getIp4Address().toIpPrefix())
Hyunsun Moon44aac662017-02-18 02:07:01 +0900512 .build();
513
514 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Li4d5c5c32018-04-02 16:38:18 +0900515 .punt()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900516 .build();
517
sanghodc375372017-06-08 10:41:30 +0900518 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900519 appId,
520 deviceId,
521 selector,
522 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900523 PRIORITY_ICMP_RULE,
sanghodc375372017-06-08 10:41:30 +0900524 Constants.GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900525 install);
526 }
527
daniel parkee8700b2017-05-11 15:50:03 +0900528 private void setInternalRouterRules(DeviceId deviceId, String srcSegmentId, String dstSegmentId,
529 IpPrefix srcSubnet, IpPrefix dstSubnet,
530 NetworkType networkType, boolean install) {
531 TrafficSelector selector;
532 TrafficTreatment treatment;
533 switch (networkType) {
534 case VXLAN:
535 selector = DefaultTrafficSelector.builder()
536 .matchEthType(Ethernet.TYPE_IPV4)
537 .matchTunnelId(Long.parseLong(srcSegmentId))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900538 .matchIPSrc(srcSubnet.getIp4Prefix())
539 .matchIPDst(dstSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900540 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900541
daniel parkee8700b2017-05-11 15:50:03 +0900542 treatment = DefaultTrafficTreatment.builder()
543 .setTunnelId(Long.parseLong(dstSegmentId))
Jian Li8abf2fe2018-06-12 18:42:30 +0900544 .transition(STAT_OUTBOUND_TABLE)
daniel parkee8700b2017-05-11 15:50:03 +0900545 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900546
sanghodc375372017-06-08 10:41:30 +0900547 osFlowRuleService.setRule(
daniel parkee8700b2017-05-11 15:50:03 +0900548 appId,
549 deviceId,
550 selector,
551 treatment,
daniel parkee8700b2017-05-11 15:50:03 +0900552 PRIORITY_INTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900553 ROUTING_TABLE,
daniel parkee8700b2017-05-11 15:50:03 +0900554 install);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900555
daniel parkee8700b2017-05-11 15:50:03 +0900556 selector = DefaultTrafficSelector.builder()
557 .matchEthType(Ethernet.TYPE_IPV4)
558 .matchTunnelId(Long.parseLong(dstSegmentId))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900559 .matchIPSrc(srcSubnet.getIp4Prefix())
560 .matchIPDst(dstSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900561 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900562
daniel parkee8700b2017-05-11 15:50:03 +0900563 treatment = DefaultTrafficTreatment.builder()
564 .setTunnelId(Long.parseLong(dstSegmentId))
Jian Li8abf2fe2018-06-12 18:42:30 +0900565 .transition(STAT_OUTBOUND_TABLE)
daniel parkee8700b2017-05-11 15:50:03 +0900566 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900567
sanghodc375372017-06-08 10:41:30 +0900568 osFlowRuleService.setRule(
daniel parkee8700b2017-05-11 15:50:03 +0900569 appId,
570 deviceId,
571 selector,
572 treatment,
daniel parkee8700b2017-05-11 15:50:03 +0900573 PRIORITY_INTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900574 ROUTING_TABLE,
daniel parkee8700b2017-05-11 15:50:03 +0900575 install);
576 break;
577 case VLAN:
578 selector = DefaultTrafficSelector.builder()
579 .matchEthType(Ethernet.TYPE_IPV4)
580 .matchVlanId(VlanId.vlanId(srcSegmentId))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900581 .matchIPSrc(srcSubnet.getIp4Prefix())
582 .matchIPDst(dstSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900583 .build();
584
585 treatment = DefaultTrafficTreatment.builder()
586 .setVlanId(VlanId.vlanId(dstSegmentId))
Jian Li8abf2fe2018-06-12 18:42:30 +0900587 .transition(STAT_OUTBOUND_TABLE)
daniel parkee8700b2017-05-11 15:50:03 +0900588 .build();
589
sanghodc375372017-06-08 10:41:30 +0900590 osFlowRuleService.setRule(
daniel parkee8700b2017-05-11 15:50:03 +0900591 appId,
592 deviceId,
593 selector,
594 treatment,
daniel parkee8700b2017-05-11 15:50:03 +0900595 PRIORITY_INTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900596 ROUTING_TABLE,
daniel parkee8700b2017-05-11 15:50:03 +0900597 install);
598
599 selector = DefaultTrafficSelector.builder()
600 .matchEthType(Ethernet.TYPE_IPV4)
601 .matchVlanId(VlanId.vlanId(dstSegmentId))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900602 .matchIPSrc(srcSubnet.getIp4Prefix())
603 .matchIPDst(dstSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900604 .build();
605
606 treatment = DefaultTrafficTreatment.builder()
607 .setVlanId(VlanId.vlanId(dstSegmentId))
Jian Li8abf2fe2018-06-12 18:42:30 +0900608 .transition(STAT_OUTBOUND_TABLE)
daniel parkee8700b2017-05-11 15:50:03 +0900609 .build();
610
sanghodc375372017-06-08 10:41:30 +0900611 osFlowRuleService.setRule(
daniel parkee8700b2017-05-11 15:50:03 +0900612 appId,
613 deviceId,
614 selector,
615 treatment,
daniel parkee8700b2017-05-11 15:50:03 +0900616 PRIORITY_INTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900617 ROUTING_TABLE,
daniel parkee8700b2017-05-11 15:50:03 +0900618 install);
619 break;
620 default:
Jian Li71670d12018-03-02 21:31:07 +0900621 final String error = String.format("%s %s",
622 ERR_UNSUPPORTED_NET_TYPE,
daniel parkee8700b2017-05-11 15:50:03 +0900623 networkType.toString());
624 throw new IllegalStateException(error);
625 }
626
Hyunsun Moon44aac662017-02-18 02:07:01 +0900627 }
628
Hyunsun Moon0d457362017-06-27 17:19:41 +0900629 private void setRulesToGateway(OpenstackNode osNode, String segmentId, IpPrefix srcSubnet,
daniel parkee8700b2017-05-11 15:50:03 +0900630 NetworkType networkType, boolean install) {
631 TrafficTreatment treatment;
daniel parkb5817102018-02-15 00:18:51 +0900632 OpenstackNode sourceNatGateway = osNodeService.completeNodes(GATEWAY).stream().findFirst().orElse(null);
633
634 if (sourceNatGateway == null) {
635 return;
636 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900637
daniel parkee8700b2017-05-11 15:50:03 +0900638 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
639 .matchEthType(Ethernet.TYPE_IPV4)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900640 .matchIPSrc(srcSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900641 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
642
643 switch (networkType) {
644 case VXLAN:
645 sBuilder.matchTunnelId(Long.parseLong(segmentId));
daniel parkee8700b2017-05-11 15:50:03 +0900646 break;
647 case VLAN:
648 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
daniel parkee8700b2017-05-11 15:50:03 +0900649 break;
650 default:
Jian Li71670d12018-03-02 21:31:07 +0900651 final String error = String.format("%s %s",
652 ERR_UNSUPPORTED_NET_TYPE,
daniel parkee8700b2017-05-11 15:50:03 +0900653 networkType.toString());
654 throw new IllegalStateException(error);
655 }
656
Daniel Parkc64b4c62018-05-09 18:13:39 +0900657 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
658
659 switch (networkType) {
660 case VXLAN:
661 tBuilder.extension(buildExtension(
662 deviceService,
663 osNode.intgBridge(),
664 sourceNatGateway.dataIp().getIp4Address()),
665 osNode.intgBridge())
666 .setOutput(osNode.tunnelPortNum());
667 break;
668
669 case VLAN:
670 tBuilder.setOutput(osNode.vlanPortNum());
671 break;
672
673 default:
674 break;
675 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900676
sanghodc375372017-06-08 10:41:30 +0900677 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900678 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900679 osNode.intgBridge(),
daniel parkee8700b2017-05-11 15:50:03 +0900680 sBuilder.build(),
Daniel Parkc64b4c62018-05-09 18:13:39 +0900681 tBuilder.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900682 PRIORITY_EXTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900683 ROUTING_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900684 install);
685 }
686
sangho072c4dd2017-05-17 10:45:21 +0900687 private void setRulesForSnatIngressRule(DeviceId deviceId, Long vni, IpPrefix destVmIp,
688 DeviceId dstDeviceId, boolean install) {
689
690 TrafficSelector selector = DefaultTrafficSelector.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900691 .matchEthType(Ethernet.TYPE_IPV4)
sangho072c4dd2017-05-17 10:45:21 +0900692 .matchIPDst(destVmIp)
693 .build();
Hyunsun Moon0d457362017-06-27 17:19:41 +0900694
sangho072c4dd2017-05-17 10:45:21 +0900695 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
696 .setTunnelId(vni)
697 .extension(buildExtension(
698 deviceService,
699 deviceId,
700 osNodeService.node(dstDeviceId).dataIp().getIp4Address()),
701 deviceId)
702 .setOutput(osNodeService.node(deviceId).tunnelPortNum())
703 .build();
daniel parkee8700b2017-05-11 15:50:03 +0900704
sanghodc375372017-06-08 10:41:30 +0900705 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900706 appId,
sangho072c4dd2017-05-17 10:45:21 +0900707 deviceId,
708 selector,
709 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900710 PRIORITY_EXTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900711 Constants.GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900712 install);
713 }
714
daniel parkb5817102018-02-15 00:18:51 +0900715 private void setRulesToGatewayWithDstIp(OpenstackNode osNode, OpenstackNode sourceNatGateway,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900716 String segmentId, IpAddress dstIp,
717 NetworkMode networkMode, boolean install) {
Daniel Parkc64b4c62018-05-09 18:13:39 +0900718 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
719 .matchEthType(Ethernet.TYPE_IPV4)
720 .matchIPDst(dstIp.getIp4Address().toIpPrefix());
721
722 switch (networkMode) {
723 case VXLAN:
724 sBuilder.matchTunnelId(Long.valueOf(segmentId));
725 break;
726
727 case VLAN:
728 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
729 break;
730
731 default:
732 break;
daniel parkee8700b2017-05-11 15:50:03 +0900733 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900734
Daniel Parkc64b4c62018-05-09 18:13:39 +0900735 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
736
737 switch (networkMode) {
738 case VXLAN:
739 tBuilder.extension(buildExtension(
daniel parkb5817102018-02-15 00:18:51 +0900740 deviceService,
741 osNode.intgBridge(),
742 sourceNatGateway.dataIp().getIp4Address()),
743 osNode.intgBridge())
Daniel Parkc64b4c62018-05-09 18:13:39 +0900744 .setOutput(osNode.tunnelPortNum());
745 break;
746
747 case VLAN:
748 tBuilder.setOutput(osNode.vlanPortNum());
749 break;
750
751 default:
752 break;
753 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900754
sanghodc375372017-06-08 10:41:30 +0900755 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900756 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900757 osNode.intgBridge(),
Daniel Parkc64b4c62018-05-09 18:13:39 +0900758 sBuilder.build(),
759 tBuilder.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900760 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900761 ROUTING_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900762 install);
763 }
764
sangho072c4dd2017-05-17 10:45:21 +0900765 private void setOvsNatIngressRule(DeviceId deviceId, IpPrefix cidr, MacAddress dstMac, boolean install) {
766
767 TrafficSelector selector = DefaultTrafficSelector.builder()
768 .matchEthType(Ethernet.TYPE_IPV4)
769 .matchIPDst(cidr)
770 .build();
771
Jian Liedc8b762018-03-22 15:42:00 +0900772 ExtensionTreatment natTreatment = RulePopulatorUtil
773 .niciraConnTrackTreatmentBuilder(driverService, deviceId)
sangho072c4dd2017-05-17 10:45:21 +0900774 .commit(false)
775 .natAction(true)
776 .table((short) 0)
777 .build();
778
779 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
780 .setEthDst(dstMac)
781 .extension(natTreatment, deviceId)
782 .build();
783
784 osFlowRuleService.setRule(
785 appId,
786 deviceId,
787 selector,
788 treatment,
sanghoe765ce22017-06-23 17:54:57 +0900789 PRIORITY_STATEFUL_SNAT_RULE,
sangho072c4dd2017-05-17 10:45:21 +0900790 GW_COMMON_TABLE,
791 install);
792 }
793
794 private void setOvsNatEgressRule(DeviceId deviceId, IpAddress natAddress, long vni, PortNumber output,
795 boolean install) {
796
797 TrafficSelector selector = DefaultTrafficSelector.builder()
798 .matchEthType(Ethernet.TYPE_IPV4)
799 .matchEthDst(DEFAULT_GATEWAY_MAC)
800 .matchTunnelId(vni)
801 .build();
802
Jian Liedc8b762018-03-22 15:42:00 +0900803 ExtensionTreatment natTreatment = RulePopulatorUtil
804 .niciraConnTrackTreatmentBuilder(driverService, deviceId)
sangho072c4dd2017-05-17 10:45:21 +0900805 .commit(true)
806 .natAction(true)
807 .natIp(natAddress)
808 .build();
809
810 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
811 .extension(natTreatment, deviceId)
812 .setEthDst(DEFAULT_EXTERNAL_ROUTER_MAC)
813 .setEthSrc(DEFAULT_GATEWAY_MAC)
814 .setOutput(output)
815 .build();
816
817 osFlowRuleService.setRule(
818 appId,
819 deviceId,
820 selector,
821 treatment,
sanghoe765ce22017-06-23 17:54:57 +0900822 PRIORITY_STATEFUL_SNAT_RULE,
sangho072c4dd2017-05-17 10:45:21 +0900823 GW_COMMON_TABLE,
824 install);
825 }
826
sanghoe765ce22017-06-23 17:54:57 +0900827 private void setRulesToController(DeviceId deviceId, String segmentId, IpPrefix srcSubnet,
828 NetworkType networkType, boolean install) {
829 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
830 .matchEthType(Ethernet.TYPE_IPV4)
Daniel Parkc64b4c62018-05-09 18:13:39 +0900831 .matchIPSrc(srcSubnet)
832 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
833
sanghoe765ce22017-06-23 17:54:57 +0900834
835 switch (networkType) {
836 case VXLAN:
Daniel Parkc64b4c62018-05-09 18:13:39 +0900837 sBuilder.matchTunnelId(Long.parseLong(segmentId));
sanghoe765ce22017-06-23 17:54:57 +0900838 break;
839 case VLAN:
Daniel Parkc64b4c62018-05-09 18:13:39 +0900840 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
sanghoe765ce22017-06-23 17:54:57 +0900841 break;
842 default:
Jian Li71670d12018-03-02 21:31:07 +0900843 final String error = String.format("%s %s",
844 ERR_UNSUPPORTED_NET_TYPE,
sanghoe765ce22017-06-23 17:54:57 +0900845 networkType.toString());
846 throw new IllegalStateException(error);
847 }
848
Daniel Parkc64b4c62018-05-09 18:13:39 +0900849 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
sanghoe765ce22017-06-23 17:54:57 +0900850
851 if (networkType.equals(NetworkType.VLAN)) {
852 tBuilder.popVlan();
853 }
854
Jian Li4d5c5c32018-04-02 16:38:18 +0900855 tBuilder.punt();
sanghoe765ce22017-06-23 17:54:57 +0900856
857 osFlowRuleService.setRule(
858 appId,
859 deviceId,
860 sBuilder.build(),
861 tBuilder.build(),
862 PRIORITY_EXTERNAL_ROUTING_RULE,
863 GW_COMMON_TABLE,
864 install);
865
866
867 // Sends ICMP response to controller for SNATing ingress traffic
868 TrafficSelector selector = DefaultTrafficSelector.builder()
869 .matchEthType(Ethernet.TYPE_IPV4)
870 .matchIPProtocol(IPv4.PROTOCOL_ICMP)
871 .matchIcmpType(ICMP.TYPE_ECHO_REPLY)
872 .build();
873
874 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Li4d5c5c32018-04-02 16:38:18 +0900875 .punt()
sanghoe765ce22017-06-23 17:54:57 +0900876 .build();
877
878 osFlowRuleService.setRule(
879 appId,
880 deviceId,
881 selector,
882 treatment,
883 PRIORITY_INTERNAL_ROUTING_RULE,
884 GW_COMMON_TABLE,
885 install);
886 }
sangho072c4dd2017-05-17 10:45:21 +0900887
Frank Wang245a6822017-06-14 09:51:35 +0800888 private void setRouterAdminRules(String segmentId, NetworkType networkType, boolean install) {
889 TrafficTreatment treatment;
890 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
891 .matchEthType(Ethernet.TYPE_IPV4);
892
893 switch (networkType) {
894 case VXLAN:
895 sBuilder.matchTunnelId(Long.parseLong(segmentId));
896 break;
897 case VLAN:
898 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
899 break;
900 default:
Jian Li71670d12018-03-02 21:31:07 +0900901 final String error = String.format("%s %s",
902 ERR_UNSUPPORTED_NET_TYPE,
Frank Wang245a6822017-06-14 09:51:35 +0800903 networkType.toString());
904 throw new IllegalStateException(error);
905 }
906
907 treatment = DefaultTrafficTreatment.builder()
908 .drop()
909 .build();
910
911 osNodeService.completeNodes().stream()
912 .filter(osNode -> osNode.type() == COMPUTE)
913 .forEach(osNode -> {
914 osFlowRuleService.setRule(
915 appId,
916 osNode.intgBridge(),
917 sBuilder.build(),
918 treatment,
919 PRIORITY_ADMIN_RULE,
920 ROUTING_TABLE,
921 install);
922 });
923 }
924
Hyunsun Moon44aac662017-02-18 02:07:01 +0900925 private class InternalRouterEventListener implements OpenstackRouterListener {
926
927 @Override
928 public boolean isRelevant(OpenstackRouterEvent event) {
929 // do not allow to proceed without leadership
930 NodeId leader = leadershipService.getLeader(appId.name());
931 return Objects.equals(localNodeId, leader);
932 }
933
934 // FIXME only one leader in the cluster should process
935 @Override
936 public void event(OpenstackRouterEvent event) {
937 switch (event.type()) {
938 case OPENSTACK_ROUTER_CREATED:
939 log.debug("Router(name:{}, ID:{}) is created",
940 event.subject().getName(),
941 event.subject().getId());
942 eventExecutor.execute(() -> routerUpdated(event.subject()));
943 break;
944 case OPENSTACK_ROUTER_UPDATED:
945 log.debug("Router(name:{}, ID:{}) is updated",
946 event.subject().getName(),
947 event.subject().getId());
948 eventExecutor.execute(() -> routerUpdated(event.subject()));
949 break;
950 case OPENSTACK_ROUTER_REMOVED:
951 log.debug("Router(name:{}, ID:{}) is removed",
952 event.subject().getName(),
953 event.subject().getId());
Frank Wang245a6822017-06-14 09:51:35 +0800954 eventExecutor.execute(() -> routerRemove(event.subject()));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900955 break;
956 case OPENSTACK_ROUTER_INTERFACE_ADDED:
957 log.debug("Router interface {} added to router {}",
958 event.routerIface().getPortId(),
959 event.routerIface().getId());
960 eventExecutor.execute(() -> routerIfaceAdded(
961 event.subject(),
962 event.routerIface()));
963 break;
964 case OPENSTACK_ROUTER_INTERFACE_UPDATED:
965 log.debug("Router interface {} on {} updated",
966 event.routerIface().getPortId(),
967 event.routerIface().getId());
968 break;
969 case OPENSTACK_ROUTER_INTERFACE_REMOVED:
970 log.debug("Router interface {} removed from router {}",
971 event.routerIface().getPortId(),
972 event.routerIface().getId());
973 eventExecutor.execute(() -> routerIfaceRemoved(
974 event.subject(),
975 event.routerIface()));
976 break;
977 case OPENSTACK_ROUTER_GATEWAY_ADDED:
daniel parkb5817102018-02-15 00:18:51 +0900978 log.debug("Router external gateway {} added", event.externalGateway().getNetworkId());
Ray Milkey08932a72018-02-20 15:34:38 -0800979 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900980 case OPENSTACK_ROUTER_GATEWAY_REMOVED:
daniel parkb5817102018-02-15 00:18:51 +0900981 log.debug("Router external gateway {} removed", event.externalGateway().getNetworkId());
Ray Milkey08932a72018-02-20 15:34:38 -0800982 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900983 case OPENSTACK_FLOATING_IP_CREATED:
984 case OPENSTACK_FLOATING_IP_UPDATED:
985 case OPENSTACK_FLOATING_IP_REMOVED:
986 case OPENSTACK_FLOATING_IP_ASSOCIATED:
987 case OPENSTACK_FLOATING_IP_DISASSOCIATED:
988 default:
989 // do nothing for the other events
990 break;
991 }
992 }
993 }
994
995 private class InternalNodeEventListener implements OpenstackNodeListener {
996
997 @Override
998 public boolean isRelevant(OpenstackNodeEvent event) {
999 // do not allow to proceed without leadership
1000 NodeId leader = leadershipService.getLeader(appId.name());
1001 return Objects.equals(localNodeId, leader);
1002 }
1003
1004 @Override
1005 public void event(OpenstackNodeEvent event) {
1006 OpenstackNode osNode = event.subject();
1007
1008 switch (event.type()) {
Hyunsun Moon0d457362017-06-27 17:19:41 +09001009 case OPENSTACK_NODE_COMPLETE:
1010 case OPENSTACK_NODE_INCOMPLETE:
Hyunsun Moon44aac662017-02-18 02:07:01 +09001011 eventExecutor.execute(() -> {
Hyunsun Moon0e058f22017-04-19 17:00:52 +09001012 log.info("Reconfigure routers for {}", osNode.hostname());
Hyunsun Moon44aac662017-02-18 02:07:01 +09001013 reconfigureRouters();
1014 });
1015 break;
Hyunsun Moon0d457362017-06-27 17:19:41 +09001016 case OPENSTACK_NODE_CREATED:
1017 case OPENSTACK_NODE_UPDATED:
1018 case OPENSTACK_NODE_REMOVED:
Hyunsun Moon44aac662017-02-18 02:07:01 +09001019 default:
1020 break;
1021 }
1022 }
1023
1024 private void reconfigureRouters() {
1025 osRouterService.routers().forEach(osRouter -> {
1026 routerUpdated(osRouter);
1027 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
1028 routerIfaceAdded(osRouter, iface);
1029 });
1030 });
1031 }
1032 }
sangho072c4dd2017-05-17 10:45:21 +09001033
1034 private class InternalInstancePortListener implements InstancePortListener {
1035
1036 @Override
1037 public boolean isRelevant(InstancePortEvent event) {
1038 InstancePort instPort = event.subject();
1039 return mastershipService.isLocalMaster(instPort.deviceId());
1040 }
1041
1042 @Override
1043 public void event(InstancePortEvent event) {
1044 InstancePort instPort = event.subject();
1045 switch (event.type()) {
1046 case OPENSTACK_INSTANCE_PORT_UPDATED:
1047 case OPENSTACK_INSTANCE_PORT_DETECTED:
1048 eventExecutor.execute(() -> {
1049 log.info("RoutingHandler: Instance port detected MAC:{} IP:{}",
1050 instPort.macAddress(),
1051 instPort.ipAddress());
1052 instPortDetected(event.subject());
1053 });
1054 break;
1055 case OPENSTACK_INSTANCE_PORT_VANISHED:
1056 eventExecutor.execute(() -> {
1057 log.info("RoutingHandler: Instance port vanished MAC:{} IP:{}",
1058 instPort.macAddress(),
1059 instPort.ipAddress());
1060 instPortRemoved(event.subject());
1061 });
1062 break;
Jian Li24ec59f2018-05-23 19:01:25 +09001063 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
1064 eventExecutor.execute(() -> {
1065 log.info("RoutingHandler: Instance port vanished MAC:{} IP:{} due to VM migration",
1066 instPort.macAddress(),
1067 instPort.ipAddress());
1068 // TODO: need to reconfigure rules to point to update VM
1069 });
1070 break;
sangho072c4dd2017-05-17 10:45:21 +09001071 default:
1072 break;
1073 }
1074 }
1075
1076 private void instPortDetected(InstancePort instPort) {
daniel park796c2eb2018-03-22 17:01:51 +09001077 if (osNetworkAdminService.network(instPort.networkId()).getNetworkType() == NetworkType.FLAT) {
1078 return;
1079 }
Daniel Parkc64b4c62018-05-09 18:13:39 +09001080
1081 if (useStatefulSnat) {
1082 osNodeService.completeNodes(GATEWAY)
1083 .forEach(gwNode -> setRulesForSnatIngressRule(
1084 gwNode.intgBridge(),
1085 Long.parseLong(osNetworkAdminService
1086 .network(instPort.networkId()).getProviderSegID()),
1087 IpPrefix.valueOf(instPort.ipAddress(), 32),
1088 instPort.deviceId(), true));
1089 }
sangho072c4dd2017-05-17 10:45:21 +09001090 }
1091
1092 private void instPortRemoved(InstancePort instPort) {
daniel park796c2eb2018-03-22 17:01:51 +09001093 if (osNetworkAdminService.network(instPort.networkId()).getNetworkType() == NetworkType.FLAT) {
1094 return;
1095 }
Daniel Parkc64b4c62018-05-09 18:13:39 +09001096
1097 if (useStatefulSnat) {
1098 osNodeService.completeNodes(GATEWAY)
1099 .forEach(gwNode -> setRulesForSnatIngressRule(
1100 gwNode.intgBridge(),
1101 Long.parseLong(osNetworkAdminService
1102 .network(instPort.networkId()).getProviderSegID()),
1103 IpPrefix.valueOf(instPort.ipAddress(), 32),
1104 instPort.deviceId(), false));
1105 }
sangho072c4dd2017-05-17 10:45:21 +09001106 }
1107 }
Hyunsun Moon44aac662017-02-18 02:07:01 +09001108}