blob: 1c7b2ecfae95943bb6fdf80b8d7b5cb4a8100f92 [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;
89import static org.onosproject.openstacknetworking.api.Constants.FORWARDING_TABLE;
90import 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 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
daniel park576969a2018-03-09 07:07:41 +0900216
Jian Liedc8b762018-03-22 15:42:00 +0900217 ExternalPeerRouter externalPeerRouter = osNetworkAdminService.externalPeerRouter(exGateway);
daniel park576969a2018-03-09 07:07:41 +0900218 VlanId vlanId = externalPeerRouter == null ? VlanId.NONE : externalPeerRouter.externalPeerRouterVlanId();
219
Hyunsun Moon44aac662017-02-18 02:07:01 +0900220 if (exGateway == null) {
daniel park32b42202018-03-14 16:53:44 +0900221 osNetworkAdminService.deleteExternalPeerRouter(exGateway);
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
Frank Wang245a6822017-06-14 09:51:35 +0800230 private void routerRemove(Router osRouter) {
231 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
Jian Liedc8b762018-03-22 15:42:00 +0900232 Network network = osNetworkAdminService.network(osNetworkAdminService.subnet(iface.getSubnetId())
Frank Wang245a6822017-06-14 09:51:35 +0800233 .getNetworkId());
234 setRouterAdminRules(network.getProviderSegID(), network.getNetworkType(), false);
235 });
236 }
237
Hyunsun Moon44aac662017-02-18 02:07:01 +0900238 private void routerIfaceAdded(Router osRouter, RouterInterface osRouterIface) {
Jian Liedc8b762018-03-22 15:42:00 +0900239 Subnet osSubnet = osNetworkAdminService.subnet(osRouterIface.getSubnetId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900240 if (osSubnet == null) {
241 final String error = String.format(
Jian Li71670d12018-03-02 21:31:07 +0900242 "Failed to set flows for router %s: subnet %s does not exist",
Hyunsun Moon44aac662017-02-18 02:07:01 +0900243 osRouterIface.getId(),
244 osRouterIface.getSubnetId());
245 throw new IllegalStateException(error);
246 }
Frank Wang245a6822017-06-14 09:51:35 +0800247
248 if (!osRouter.isAdminStateUp()) {
Jian Liedc8b762018-03-22 15:42:00 +0900249 Network network = osNetworkAdminService.network(osSubnet.getNetworkId());
Frank Wang245a6822017-06-14 09:51:35 +0800250 setRouterAdminRules(network.getProviderSegID(), network.getNetworkType(), true);
251 }
252
Hyunsun Moon44aac662017-02-18 02:07:01 +0900253 setInternalRoutes(osRouter, osSubnet, true);
254 setGatewayIcmp(osSubnet, true);
255 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
256 if (exGateway != null && exGateway.isEnableSnat()) {
daniel park576969a2018-03-09 07:07:41 +0900257 setSourceNat(osRouterIface, true);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900258 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900259 log.info("Connected subnet({}) to {}", osSubnet.getCidr(), osRouter.getName());
260 }
261
262 private void routerIfaceRemoved(Router osRouter, RouterInterface osRouterIface) {
Jian Liedc8b762018-03-22 15:42:00 +0900263 Subnet osSubnet = osNetworkAdminService.subnet(osRouterIface.getSubnetId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900264 if (osSubnet == null) {
265 final String error = String.format(
Jian Li71670d12018-03-02 21:31:07 +0900266 "Failed to set flows for router %s: subnet %s does not exist",
Hyunsun Moon44aac662017-02-18 02:07:01 +0900267 osRouterIface.getId(),
268 osRouterIface.getSubnetId());
269 throw new IllegalStateException(error);
270 }
271
Frank Wang245a6822017-06-14 09:51:35 +0800272 if (!osRouter.isAdminStateUp()) {
Jian Liedc8b762018-03-22 15:42:00 +0900273 Network network = osNetworkAdminService.network(osSubnet.getNetworkId());
Frank Wang245a6822017-06-14 09:51:35 +0800274 setRouterAdminRules(network.getProviderSegID(), network.getNetworkType(), false);
275 }
276
Hyunsun Moon44aac662017-02-18 02:07:01 +0900277 setInternalRoutes(osRouter, osSubnet, false);
278 setGatewayIcmp(osSubnet, false);
279 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
280 if (exGateway != null && exGateway.isEnableSnat()) {
daniel park576969a2018-03-09 07:07:41 +0900281 setSourceNat(osRouterIface, false);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900282 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900283 log.info("Disconnected subnet({}) from {}", osSubnet.getCidr(), osRouter.getName());
284 }
285
daniel park576969a2018-03-09 07:07:41 +0900286 private void setSourceNat(RouterInterface routerIface, boolean install) {
Jian Liedc8b762018-03-22 15:42:00 +0900287 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
288 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900289
Hyunsun Moon0d457362017-06-27 17:19:41 +0900290 osNodeService.completeNodes(COMPUTE).forEach(cNode -> {
291 setRulesToGateway(cNode, osNet.getProviderSegID(),
292 IpPrefix.valueOf(osSubnet.getCidr()), osNet.getNetworkType(),
293 install);
294 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900295
sanghoe765ce22017-06-23 17:54:57 +0900296 if (useStatefulSnat) {
297 setStatefulSnatRules(routerIface, install);
298 } else {
299 setReactiveSnatRules(routerIface, install);
300 }
301
302 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
303 log.info(updateStr + "external access for subnet({})", osSubnet.getCidr());
304 }
305
306 private void setStatefulSnatRules(RouterInterface routerIface, boolean install) {
Jian Liedc8b762018-03-22 15:42:00 +0900307 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
308 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
sanghoe765ce22017-06-23 17:54:57 +0900309
daniel park796c2eb2018-03-22 17:01:51 +0900310 if (osNet.getNetworkType() == NetworkType.FLAT) {
311 return;
312 }
313
sanghoe765ce22017-06-23 17:54:57 +0900314 Optional<Router> osRouter = osRouterService.routers().stream()
315 .filter(router -> osRouterService.routerInterfaces(routerIface.getId()) != null)
316 .findAny();
317
318 if (!osRouter.isPresent()) {
319 log.error("Cannot find a router for router interface {} ", routerIface);
320 return;
321 }
322 IpAddress natAddress = getGatewayIpAddress(osRouter.get());
sangho072c4dd2017-05-17 10:45:21 +0900323 if (natAddress == null) {
324 return;
325 }
Jian Liedc8b762018-03-22 15:42:00 +0900326 String netId = osNetworkAdminService.subnet(routerIface.getSubnetId()).getNetworkId();
sangho072c4dd2017-05-17 10:45:21 +0900327
328 osNodeService.completeNodes(OpenstackNode.NodeType.GATEWAY)
329 .forEach(gwNode -> {
daniel park576969a2018-03-09 07:07:41 +0900330 instancePortService.instancePorts(netId)
331 .forEach(port -> setRulesForSnatIngressRule(gwNode.intgBridge(),
sangho072c4dd2017-05-17 10:45:21 +0900332 Long.parseLong(osNet.getProviderSegID()),
333 IpPrefix.valueOf(port.ipAddress(), 32),
334 port.deviceId(),
335 install));
336
337 setOvsNatIngressRule(gwNode.intgBridge(),
338 IpPrefix.valueOf(natAddress, 32),
339 Constants.DEFAULT_EXTERNAL_ROUTER_MAC, install);
340 setOvsNatEgressRule(gwNode.intgBridge(),
341 natAddress, Long.parseLong(osNet.getProviderSegID()),
342 gwNode.patchPortNum(), install);
343 });
sanghoe765ce22017-06-23 17:54:57 +0900344 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900345
sanghoe765ce22017-06-23 17:54:57 +0900346 private void setReactiveSnatRules(RouterInterface routerIface, boolean install) {
Jian Liedc8b762018-03-22 15:42:00 +0900347 Subnet osSubnet = osNetworkAdminService.subnet(routerIface.getSubnetId());
348 Network osNet = osNetworkAdminService.network(osSubnet.getNetworkId());
sanghoe765ce22017-06-23 17:54:57 +0900349
350 osNodeService.completeNodes(GATEWAY)
351 .forEach(gwNode -> setRulesToController(
352 gwNode.intgBridge(),
353 osNet.getProviderSegID(),
354 IpPrefix.valueOf(osSubnet.getCidr()),
355 osNet.getNetworkType(),
356 install));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900357 }
358
sangho072c4dd2017-05-17 10:45:21 +0900359 private IpAddress getGatewayIpAddress(Router osRouter) {
360
Jian Liedc8b762018-03-22 15:42:00 +0900361 String extNetId = osNetworkAdminService.network(osRouter.getExternalGatewayInfo().getNetworkId()).getId();
362 Optional<Subnet> extSubnet = osNetworkAdminService.subnets().stream()
sangho072c4dd2017-05-17 10:45:21 +0900363 .filter(subnet -> subnet.getNetworkId().equals(extNetId))
364 .findAny();
365
366 if (!extSubnet.isPresent()) {
367 log.error("Cannot find externel subnet for the router");
368 return null;
369 }
370
371 return IpAddress.valueOf(extSubnet.get().getGateway());
372 }
373
sanghoe765ce22017-06-23 17:54:57 +0900374 private void resetSnatRules() {
375 if (useStatefulSnat) {
376 osRouterService.routerInterfaces().forEach(
377 routerIface -> {
378 setReactiveSnatRules(routerIface, false);
379 setStatefulSnatRules(routerIface, true);
380 }
381 );
382 } else {
383 osRouterService.routerInterfaces().forEach(
384 routerIface -> {
385 setStatefulSnatRules(routerIface, false);
386 setReactiveSnatRules(routerIface, true);
387 }
388 );
389 }
390 }
391
Hyunsun Moon44aac662017-02-18 02:07:01 +0900392 private void setGatewayIcmp(Subnet osSubnet, boolean install) {
daniel parkb5817102018-02-15 00:18:51 +0900393 OpenstackNode sourceNatGateway = osNodeService.completeNodes(GATEWAY).stream().findFirst().orElse(null);
394
395 if (sourceNatGateway == null) {
396 return;
397 }
398
Hyunsun Moon44aac662017-02-18 02:07:01 +0900399 if (Strings.isNullOrEmpty(osSubnet.getGateway())) {
400 // do nothing if no gateway is set
401 return;
402 }
403
404 // take ICMP request to a subnet gateway through gateway node group
Jian Liedc8b762018-03-22 15:42:00 +0900405 Network network = osNetworkAdminService.network(osSubnet.getNetworkId());
daniel parkee8700b2017-05-11 15:50:03 +0900406 switch (network.getNetworkType()) {
407 case VXLAN:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900408 osNodeService.completeNodes(COMPUTE).stream()
409 .filter(cNode -> cNode.dataIp() != null)
410 .forEach(cNode -> setRulesToGatewayWithDstIp(
411 cNode,
daniel parkb5817102018-02-15 00:18:51 +0900412 sourceNatGateway,
daniel parkee8700b2017-05-11 15:50:03 +0900413 network.getProviderSegID(),
414 IpAddress.valueOf(osSubnet.getGateway()),
415 NetworkMode.VXLAN,
416 install));
417 break;
418 case VLAN:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900419 osNodeService.completeNodes(COMPUTE).stream()
420 .filter(cNode -> cNode.vlanPortNum() != null)
421 .forEach(cNode -> setRulesToGatewayWithDstIp(
422 cNode,
daniel parkb5817102018-02-15 00:18:51 +0900423 sourceNatGateway,
daniel parkee8700b2017-05-11 15:50:03 +0900424 network.getProviderSegID(),
425 IpAddress.valueOf(osSubnet.getGateway()),
426 NetworkMode.VLAN,
427 install));
428 break;
429 default:
Jian Li71670d12018-03-02 21:31:07 +0900430 final String error = String.format("%s %s",
431 ERR_UNSUPPORTED_NET_TYPE,
daniel parkee8700b2017-05-11 15:50:03 +0900432 network.getNetworkType().toString());
433 throw new IllegalStateException(error);
434 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900435
436 IpAddress gatewayIp = IpAddress.valueOf(osSubnet.getGateway());
daniel park576969a2018-03-09 07:07:41 +0900437 osNodeService.completeNodes(GATEWAY).forEach(gNode ->
Hyunsun Moon0d457362017-06-27 17:19:41 +0900438 setGatewayIcmpRule(
439 gatewayIp,
440 gNode.intgBridge(),
daniel park576969a2018-03-09 07:07:41 +0900441 install));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900442
443 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
444 log.debug(updateStr + "ICMP to {}", osSubnet.getGateway());
445 }
446
447 private void setInternalRoutes(Router osRouter, Subnet updatedSubnet, boolean install) {
Jian Liedc8b762018-03-22 15:42:00 +0900448 Network updatedNetwork = osNetworkAdminService.network(updatedSubnet.getNetworkId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900449 Set<Subnet> routableSubnets = routableSubnets(osRouter, updatedSubnet.getId());
daniel parkee8700b2017-05-11 15:50:03 +0900450 String updatedSegmendId = getSegmentId(updatedSubnet);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900451
452 // installs rule from/to my subnet intentionally to fix ICMP failure
453 // to my subnet gateway if no external gateway added to the router
Hyunsun Moon0d457362017-06-27 17:19:41 +0900454 osNodeService.completeNodes(COMPUTE).forEach(cNode -> {
455 setInternalRouterRules(
456 cNode.intgBridge(),
457 updatedSegmendId,
458 updatedSegmendId,
459 IpPrefix.valueOf(updatedSubnet.getCidr()),
460 IpPrefix.valueOf(updatedSubnet.getCidr()),
461 updatedNetwork.getNetworkType(),
462 install
463 );
Hyunsun Moon44aac662017-02-18 02:07:01 +0900464
Hyunsun Moon0d457362017-06-27 17:19:41 +0900465 routableSubnets.forEach(subnet -> {
466 setInternalRouterRules(
467 cNode.intgBridge(),
468 updatedSegmendId,
469 getSegmentId(subnet),
470 IpPrefix.valueOf(updatedSubnet.getCidr()),
471 IpPrefix.valueOf(subnet.getCidr()),
472 updatedNetwork.getNetworkType(),
473 install
474 );
475 setInternalRouterRules(
476 cNode.intgBridge(),
477 getSegmentId(subnet),
478 updatedSegmendId,
479 IpPrefix.valueOf(subnet.getCidr()),
480 IpPrefix.valueOf(updatedSubnet.getCidr()),
481 updatedNetwork.getNetworkType(),
482 install
483 );
484 });
485 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900486
daniel parkee8700b2017-05-11 15:50:03 +0900487
Hyunsun Moon44aac662017-02-18 02:07:01 +0900488 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
489 routableSubnets.forEach(subnet -> log.debug(
490 updateStr + "route between subnet:{} and subnet:{}",
491 subnet.getCidr(),
492 updatedSubnet.getCidr()));
493 }
494
495 private Set<Subnet> routableSubnets(Router osRouter, String osSubnetId) {
496 Set<Subnet> osSubnets = osRouterService.routerInterfaces(osRouter.getId())
497 .stream()
498 .filter(iface -> !Objects.equals(iface.getSubnetId(), osSubnetId))
Jian Liedc8b762018-03-22 15:42:00 +0900499 .map(iface -> osNetworkAdminService.subnet(iface.getSubnetId()))
Hyunsun Moon44aac662017-02-18 02:07:01 +0900500 .collect(Collectors.toSet());
501 return ImmutableSet.copyOf(osSubnets);
502 }
503
daniel parkee8700b2017-05-11 15:50:03 +0900504 private String getSegmentId(Subnet osSubnet) {
Jian Liedc8b762018-03-22 15:42:00 +0900505 return osNetworkAdminService.network(osSubnet.getNetworkId()).getProviderSegID();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900506 }
507
508 private void setGatewayIcmpRule(IpAddress gatewayIp, DeviceId deviceId, boolean install) {
509 TrafficSelector selector = DefaultTrafficSelector.builder()
510 .matchEthType(Ethernet.TYPE_IPV4)
511 .matchIPProtocol(IPv4.PROTOCOL_ICMP)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900512 .matchIPDst(gatewayIp.getIp4Address().toIpPrefix())
Hyunsun Moon44aac662017-02-18 02:07:01 +0900513 .build();
514
515 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Li4d5c5c32018-04-02 16:38:18 +0900516 .punt()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900517 .build();
518
sanghodc375372017-06-08 10:41:30 +0900519 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900520 appId,
521 deviceId,
522 selector,
523 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900524 PRIORITY_ICMP_RULE,
sanghodc375372017-06-08 10:41:30 +0900525 Constants.GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900526 install);
527 }
528
daniel parkee8700b2017-05-11 15:50:03 +0900529 private void setInternalRouterRules(DeviceId deviceId, String srcSegmentId, String dstSegmentId,
530 IpPrefix srcSubnet, IpPrefix dstSubnet,
531 NetworkType networkType, boolean install) {
532 TrafficSelector selector;
533 TrafficTreatment treatment;
534 switch (networkType) {
535 case VXLAN:
536 selector = DefaultTrafficSelector.builder()
537 .matchEthType(Ethernet.TYPE_IPV4)
538 .matchTunnelId(Long.parseLong(srcSegmentId))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900539 .matchIPSrc(srcSubnet.getIp4Prefix())
540 .matchIPDst(dstSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900541 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900542
daniel parkee8700b2017-05-11 15:50:03 +0900543 treatment = DefaultTrafficTreatment.builder()
544 .setTunnelId(Long.parseLong(dstSegmentId))
sanghodc375372017-06-08 10:41:30 +0900545 .transition(FORWARDING_TABLE)
daniel parkee8700b2017-05-11 15:50:03 +0900546 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900547
sanghodc375372017-06-08 10:41:30 +0900548 osFlowRuleService.setRule(
daniel parkee8700b2017-05-11 15:50:03 +0900549 appId,
550 deviceId,
551 selector,
552 treatment,
daniel parkee8700b2017-05-11 15:50:03 +0900553 PRIORITY_INTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900554 ROUTING_TABLE,
daniel parkee8700b2017-05-11 15:50:03 +0900555 install);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900556
daniel parkee8700b2017-05-11 15:50:03 +0900557 selector = DefaultTrafficSelector.builder()
558 .matchEthType(Ethernet.TYPE_IPV4)
559 .matchTunnelId(Long.parseLong(dstSegmentId))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900560 .matchIPSrc(srcSubnet.getIp4Prefix())
561 .matchIPDst(dstSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900562 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900563
daniel parkee8700b2017-05-11 15:50:03 +0900564 treatment = DefaultTrafficTreatment.builder()
565 .setTunnelId(Long.parseLong(dstSegmentId))
sanghodc375372017-06-08 10:41:30 +0900566 .transition(FORWARDING_TABLE)
daniel parkee8700b2017-05-11 15:50:03 +0900567 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900568
sanghodc375372017-06-08 10:41:30 +0900569 osFlowRuleService.setRule(
daniel parkee8700b2017-05-11 15:50:03 +0900570 appId,
571 deviceId,
572 selector,
573 treatment,
daniel parkee8700b2017-05-11 15:50:03 +0900574 PRIORITY_INTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900575 ROUTING_TABLE,
daniel parkee8700b2017-05-11 15:50:03 +0900576 install);
577 break;
578 case VLAN:
579 selector = DefaultTrafficSelector.builder()
580 .matchEthType(Ethernet.TYPE_IPV4)
581 .matchVlanId(VlanId.vlanId(srcSegmentId))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900582 .matchIPSrc(srcSubnet.getIp4Prefix())
583 .matchIPDst(dstSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900584 .build();
585
586 treatment = DefaultTrafficTreatment.builder()
587 .setVlanId(VlanId.vlanId(dstSegmentId))
sanghodc375372017-06-08 10:41:30 +0900588 .transition(FORWARDING_TABLE)
daniel parkee8700b2017-05-11 15:50:03 +0900589 .build();
590
sanghodc375372017-06-08 10:41:30 +0900591 osFlowRuleService.setRule(
daniel parkee8700b2017-05-11 15:50:03 +0900592 appId,
593 deviceId,
594 selector,
595 treatment,
daniel parkee8700b2017-05-11 15:50:03 +0900596 PRIORITY_INTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900597 ROUTING_TABLE,
daniel parkee8700b2017-05-11 15:50:03 +0900598 install);
599
600 selector = DefaultTrafficSelector.builder()
601 .matchEthType(Ethernet.TYPE_IPV4)
602 .matchVlanId(VlanId.vlanId(dstSegmentId))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900603 .matchIPSrc(srcSubnet.getIp4Prefix())
604 .matchIPDst(dstSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900605 .build();
606
607 treatment = DefaultTrafficTreatment.builder()
608 .setVlanId(VlanId.vlanId(dstSegmentId))
sanghodc375372017-06-08 10:41:30 +0900609 .transition(FORWARDING_TABLE)
daniel parkee8700b2017-05-11 15:50:03 +0900610 .build();
611
sanghodc375372017-06-08 10:41:30 +0900612 osFlowRuleService.setRule(
daniel parkee8700b2017-05-11 15:50:03 +0900613 appId,
614 deviceId,
615 selector,
616 treatment,
daniel parkee8700b2017-05-11 15:50:03 +0900617 PRIORITY_INTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900618 ROUTING_TABLE,
daniel parkee8700b2017-05-11 15:50:03 +0900619 install);
620 break;
621 default:
Jian Li71670d12018-03-02 21:31:07 +0900622 final String error = String.format("%s %s",
623 ERR_UNSUPPORTED_NET_TYPE,
daniel parkee8700b2017-05-11 15:50:03 +0900624 networkType.toString());
625 throw new IllegalStateException(error);
626 }
627
Hyunsun Moon44aac662017-02-18 02:07:01 +0900628 }
629
Hyunsun Moon0d457362017-06-27 17:19:41 +0900630 private void setRulesToGateway(OpenstackNode osNode, String segmentId, IpPrefix srcSubnet,
daniel parkee8700b2017-05-11 15:50:03 +0900631 NetworkType networkType, boolean install) {
632 TrafficTreatment treatment;
daniel parkb5817102018-02-15 00:18:51 +0900633 OpenstackNode sourceNatGateway = osNodeService.completeNodes(GATEWAY).stream().findFirst().orElse(null);
634
635 if (sourceNatGateway == null) {
636 return;
637 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900638
daniel parkee8700b2017-05-11 15:50:03 +0900639 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
640 .matchEthType(Ethernet.TYPE_IPV4)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900641 .matchIPSrc(srcSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900642 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
643
644 switch (networkType) {
645 case VXLAN:
646 sBuilder.matchTunnelId(Long.parseLong(segmentId));
daniel parkee8700b2017-05-11 15:50:03 +0900647 break;
648 case VLAN:
649 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
daniel parkee8700b2017-05-11 15:50:03 +0900650 break;
651 default:
Jian Li71670d12018-03-02 21:31:07 +0900652 final String error = String.format("%s %s",
653 ERR_UNSUPPORTED_NET_TYPE,
daniel parkee8700b2017-05-11 15:50:03 +0900654 networkType.toString());
655 throw new IllegalStateException(error);
656 }
657
Daniel Parkc64b4c62018-05-09 18:13:39 +0900658 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
659
660 switch (networkType) {
661 case VXLAN:
662 tBuilder.extension(buildExtension(
663 deviceService,
664 osNode.intgBridge(),
665 sourceNatGateway.dataIp().getIp4Address()),
666 osNode.intgBridge())
667 .setOutput(osNode.tunnelPortNum());
668 break;
669
670 case VLAN:
671 tBuilder.setOutput(osNode.vlanPortNum());
672 break;
673
674 default:
675 break;
676 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900677
sanghodc375372017-06-08 10:41:30 +0900678 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900679 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900680 osNode.intgBridge(),
daniel parkee8700b2017-05-11 15:50:03 +0900681 sBuilder.build(),
Daniel Parkc64b4c62018-05-09 18:13:39 +0900682 tBuilder.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900683 PRIORITY_EXTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900684 ROUTING_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900685 install);
686 }
687
sangho072c4dd2017-05-17 10:45:21 +0900688 private void setRulesForSnatIngressRule(DeviceId deviceId, Long vni, IpPrefix destVmIp,
689 DeviceId dstDeviceId, boolean install) {
690
691 TrafficSelector selector = DefaultTrafficSelector.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900692 .matchEthType(Ethernet.TYPE_IPV4)
sangho072c4dd2017-05-17 10:45:21 +0900693 .matchIPDst(destVmIp)
694 .build();
Hyunsun Moon0d457362017-06-27 17:19:41 +0900695
sangho072c4dd2017-05-17 10:45:21 +0900696 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
697 .setTunnelId(vni)
698 .extension(buildExtension(
699 deviceService,
700 deviceId,
701 osNodeService.node(dstDeviceId).dataIp().getIp4Address()),
702 deviceId)
703 .setOutput(osNodeService.node(deviceId).tunnelPortNum())
704 .build();
daniel parkee8700b2017-05-11 15:50:03 +0900705
sanghodc375372017-06-08 10:41:30 +0900706 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900707 appId,
sangho072c4dd2017-05-17 10:45:21 +0900708 deviceId,
709 selector,
710 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900711 PRIORITY_EXTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900712 Constants.GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900713 install);
714 }
715
daniel parkb5817102018-02-15 00:18:51 +0900716 private void setRulesToGatewayWithDstIp(OpenstackNode osNode, OpenstackNode sourceNatGateway,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900717 String segmentId, IpAddress dstIp,
718 NetworkMode networkMode, boolean install) {
Daniel Parkc64b4c62018-05-09 18:13:39 +0900719 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
720 .matchEthType(Ethernet.TYPE_IPV4)
721 .matchIPDst(dstIp.getIp4Address().toIpPrefix());
722
723 switch (networkMode) {
724 case VXLAN:
725 sBuilder.matchTunnelId(Long.valueOf(segmentId));
726 break;
727
728 case VLAN:
729 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
730 break;
731
732 default:
733 break;
daniel parkee8700b2017-05-11 15:50:03 +0900734 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900735
Daniel Parkc64b4c62018-05-09 18:13:39 +0900736 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
737
738 switch (networkMode) {
739 case VXLAN:
740 tBuilder.extension(buildExtension(
daniel parkb5817102018-02-15 00:18:51 +0900741 deviceService,
742 osNode.intgBridge(),
743 sourceNatGateway.dataIp().getIp4Address()),
744 osNode.intgBridge())
Daniel Parkc64b4c62018-05-09 18:13:39 +0900745 .setOutput(osNode.tunnelPortNum());
746 break;
747
748 case VLAN:
749 tBuilder.setOutput(osNode.vlanPortNum());
750 break;
751
752 default:
753 break;
754 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900755
sanghodc375372017-06-08 10:41:30 +0900756 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900757 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900758 osNode.intgBridge(),
Daniel Parkc64b4c62018-05-09 18:13:39 +0900759 sBuilder.build(),
760 tBuilder.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900761 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900762 ROUTING_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900763 install);
764 }
765
sangho072c4dd2017-05-17 10:45:21 +0900766 private void setOvsNatIngressRule(DeviceId deviceId, IpPrefix cidr, MacAddress dstMac, boolean install) {
767
768 TrafficSelector selector = DefaultTrafficSelector.builder()
769 .matchEthType(Ethernet.TYPE_IPV4)
770 .matchIPDst(cidr)
771 .build();
772
Jian Liedc8b762018-03-22 15:42:00 +0900773 ExtensionTreatment natTreatment = RulePopulatorUtil
774 .niciraConnTrackTreatmentBuilder(driverService, deviceId)
sangho072c4dd2017-05-17 10:45:21 +0900775 .commit(false)
776 .natAction(true)
777 .table((short) 0)
778 .build();
779
780 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
781 .setEthDst(dstMac)
782 .extension(natTreatment, deviceId)
783 .build();
784
785 osFlowRuleService.setRule(
786 appId,
787 deviceId,
788 selector,
789 treatment,
sanghoe765ce22017-06-23 17:54:57 +0900790 PRIORITY_STATEFUL_SNAT_RULE,
sangho072c4dd2017-05-17 10:45:21 +0900791 GW_COMMON_TABLE,
792 install);
793 }
794
795 private void setOvsNatEgressRule(DeviceId deviceId, IpAddress natAddress, long vni, PortNumber output,
796 boolean install) {
797
798 TrafficSelector selector = DefaultTrafficSelector.builder()
799 .matchEthType(Ethernet.TYPE_IPV4)
800 .matchEthDst(DEFAULT_GATEWAY_MAC)
801 .matchTunnelId(vni)
802 .build();
803
Jian Liedc8b762018-03-22 15:42:00 +0900804 ExtensionTreatment natTreatment = RulePopulatorUtil
805 .niciraConnTrackTreatmentBuilder(driverService, deviceId)
sangho072c4dd2017-05-17 10:45:21 +0900806 .commit(true)
807 .natAction(true)
808 .natIp(natAddress)
809 .build();
810
811 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
812 .extension(natTreatment, deviceId)
813 .setEthDst(DEFAULT_EXTERNAL_ROUTER_MAC)
814 .setEthSrc(DEFAULT_GATEWAY_MAC)
815 .setOutput(output)
816 .build();
817
818 osFlowRuleService.setRule(
819 appId,
820 deviceId,
821 selector,
822 treatment,
sanghoe765ce22017-06-23 17:54:57 +0900823 PRIORITY_STATEFUL_SNAT_RULE,
sangho072c4dd2017-05-17 10:45:21 +0900824 GW_COMMON_TABLE,
825 install);
826 }
827
sanghoe765ce22017-06-23 17:54:57 +0900828 private void setRulesToController(DeviceId deviceId, String segmentId, IpPrefix srcSubnet,
829 NetworkType networkType, boolean install) {
830 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
831 .matchEthType(Ethernet.TYPE_IPV4)
Daniel Parkc64b4c62018-05-09 18:13:39 +0900832 .matchIPSrc(srcSubnet)
833 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
834
sanghoe765ce22017-06-23 17:54:57 +0900835
836 switch (networkType) {
837 case VXLAN:
Daniel Parkc64b4c62018-05-09 18:13:39 +0900838 sBuilder.matchTunnelId(Long.parseLong(segmentId));
sanghoe765ce22017-06-23 17:54:57 +0900839 break;
840 case VLAN:
Daniel Parkc64b4c62018-05-09 18:13:39 +0900841 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
sanghoe765ce22017-06-23 17:54:57 +0900842 break;
843 default:
Jian Li71670d12018-03-02 21:31:07 +0900844 final String error = String.format("%s %s",
845 ERR_UNSUPPORTED_NET_TYPE,
sanghoe765ce22017-06-23 17:54:57 +0900846 networkType.toString());
847 throw new IllegalStateException(error);
848 }
849
Daniel Parkc64b4c62018-05-09 18:13:39 +0900850 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
sanghoe765ce22017-06-23 17:54:57 +0900851
852 if (networkType.equals(NetworkType.VLAN)) {
853 tBuilder.popVlan();
854 }
855
Jian Li4d5c5c32018-04-02 16:38:18 +0900856 tBuilder.punt();
sanghoe765ce22017-06-23 17:54:57 +0900857
858 osFlowRuleService.setRule(
859 appId,
860 deviceId,
861 sBuilder.build(),
862 tBuilder.build(),
863 PRIORITY_EXTERNAL_ROUTING_RULE,
864 GW_COMMON_TABLE,
865 install);
866
867
868 // Sends ICMP response to controller for SNATing ingress traffic
869 TrafficSelector selector = DefaultTrafficSelector.builder()
870 .matchEthType(Ethernet.TYPE_IPV4)
871 .matchIPProtocol(IPv4.PROTOCOL_ICMP)
872 .matchIcmpType(ICMP.TYPE_ECHO_REPLY)
873 .build();
874
875 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Li4d5c5c32018-04-02 16:38:18 +0900876 .punt()
sanghoe765ce22017-06-23 17:54:57 +0900877 .build();
878
879 osFlowRuleService.setRule(
880 appId,
881 deviceId,
882 selector,
883 treatment,
884 PRIORITY_INTERNAL_ROUTING_RULE,
885 GW_COMMON_TABLE,
886 install);
887 }
sangho072c4dd2017-05-17 10:45:21 +0900888
Frank Wang245a6822017-06-14 09:51:35 +0800889 private void setRouterAdminRules(String segmentId, NetworkType networkType, boolean install) {
890 TrafficTreatment treatment;
891 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
892 .matchEthType(Ethernet.TYPE_IPV4);
893
894 switch (networkType) {
895 case VXLAN:
896 sBuilder.matchTunnelId(Long.parseLong(segmentId));
897 break;
898 case VLAN:
899 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
900 break;
901 default:
Jian Li71670d12018-03-02 21:31:07 +0900902 final String error = String.format("%s %s",
903 ERR_UNSUPPORTED_NET_TYPE,
Frank Wang245a6822017-06-14 09:51:35 +0800904 networkType.toString());
905 throw new IllegalStateException(error);
906 }
907
908 treatment = DefaultTrafficTreatment.builder()
909 .drop()
910 .build();
911
912 osNodeService.completeNodes().stream()
913 .filter(osNode -> osNode.type() == COMPUTE)
914 .forEach(osNode -> {
915 osFlowRuleService.setRule(
916 appId,
917 osNode.intgBridge(),
918 sBuilder.build(),
919 treatment,
920 PRIORITY_ADMIN_RULE,
921 ROUTING_TABLE,
922 install);
923 });
924 }
925
Hyunsun Moon44aac662017-02-18 02:07:01 +0900926 private class InternalRouterEventListener implements OpenstackRouterListener {
927
928 @Override
929 public boolean isRelevant(OpenstackRouterEvent event) {
930 // do not allow to proceed without leadership
931 NodeId leader = leadershipService.getLeader(appId.name());
932 return Objects.equals(localNodeId, leader);
933 }
934
935 // FIXME only one leader in the cluster should process
936 @Override
937 public void event(OpenstackRouterEvent event) {
938 switch (event.type()) {
939 case OPENSTACK_ROUTER_CREATED:
940 log.debug("Router(name:{}, ID:{}) is created",
941 event.subject().getName(),
942 event.subject().getId());
943 eventExecutor.execute(() -> routerUpdated(event.subject()));
944 break;
945 case OPENSTACK_ROUTER_UPDATED:
946 log.debug("Router(name:{}, ID:{}) is updated",
947 event.subject().getName(),
948 event.subject().getId());
949 eventExecutor.execute(() -> routerUpdated(event.subject()));
950 break;
951 case OPENSTACK_ROUTER_REMOVED:
952 log.debug("Router(name:{}, ID:{}) is removed",
953 event.subject().getName(),
954 event.subject().getId());
Frank Wang245a6822017-06-14 09:51:35 +0800955 eventExecutor.execute(() -> routerRemove(event.subject()));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900956 break;
957 case OPENSTACK_ROUTER_INTERFACE_ADDED:
958 log.debug("Router interface {} added to router {}",
959 event.routerIface().getPortId(),
960 event.routerIface().getId());
961 eventExecutor.execute(() -> routerIfaceAdded(
962 event.subject(),
963 event.routerIface()));
964 break;
965 case OPENSTACK_ROUTER_INTERFACE_UPDATED:
966 log.debug("Router interface {} on {} updated",
967 event.routerIface().getPortId(),
968 event.routerIface().getId());
969 break;
970 case OPENSTACK_ROUTER_INTERFACE_REMOVED:
971 log.debug("Router interface {} removed from router {}",
972 event.routerIface().getPortId(),
973 event.routerIface().getId());
974 eventExecutor.execute(() -> routerIfaceRemoved(
975 event.subject(),
976 event.routerIface()));
977 break;
978 case OPENSTACK_ROUTER_GATEWAY_ADDED:
daniel parkb5817102018-02-15 00:18:51 +0900979 log.debug("Router external gateway {} added", event.externalGateway().getNetworkId());
Ray Milkey08932a72018-02-20 15:34:38 -0800980 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900981 case OPENSTACK_ROUTER_GATEWAY_REMOVED:
daniel parkb5817102018-02-15 00:18:51 +0900982 log.debug("Router external gateway {} removed", event.externalGateway().getNetworkId());
Ray Milkey08932a72018-02-20 15:34:38 -0800983 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900984 case OPENSTACK_FLOATING_IP_CREATED:
985 case OPENSTACK_FLOATING_IP_UPDATED:
986 case OPENSTACK_FLOATING_IP_REMOVED:
987 case OPENSTACK_FLOATING_IP_ASSOCIATED:
988 case OPENSTACK_FLOATING_IP_DISASSOCIATED:
989 default:
990 // do nothing for the other events
991 break;
992 }
993 }
994 }
995
996 private class InternalNodeEventListener implements OpenstackNodeListener {
997
998 @Override
999 public boolean isRelevant(OpenstackNodeEvent event) {
1000 // do not allow to proceed without leadership
1001 NodeId leader = leadershipService.getLeader(appId.name());
1002 return Objects.equals(localNodeId, leader);
1003 }
1004
1005 @Override
1006 public void event(OpenstackNodeEvent event) {
1007 OpenstackNode osNode = event.subject();
1008
1009 switch (event.type()) {
Hyunsun Moon0d457362017-06-27 17:19:41 +09001010 case OPENSTACK_NODE_COMPLETE:
1011 case OPENSTACK_NODE_INCOMPLETE:
Hyunsun Moon44aac662017-02-18 02:07:01 +09001012 eventExecutor.execute(() -> {
Hyunsun Moon0e058f22017-04-19 17:00:52 +09001013 log.info("Reconfigure routers for {}", osNode.hostname());
Hyunsun Moon44aac662017-02-18 02:07:01 +09001014 reconfigureRouters();
1015 });
1016 break;
Hyunsun Moon0d457362017-06-27 17:19:41 +09001017 case OPENSTACK_NODE_CREATED:
1018 case OPENSTACK_NODE_UPDATED:
1019 case OPENSTACK_NODE_REMOVED:
Hyunsun Moon44aac662017-02-18 02:07:01 +09001020 default:
1021 break;
1022 }
1023 }
1024
1025 private void reconfigureRouters() {
1026 osRouterService.routers().forEach(osRouter -> {
1027 routerUpdated(osRouter);
1028 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
1029 routerIfaceAdded(osRouter, iface);
1030 });
1031 });
1032 }
1033 }
sangho072c4dd2017-05-17 10:45:21 +09001034
1035 private class InternalInstancePortListener implements InstancePortListener {
1036
1037 @Override
1038 public boolean isRelevant(InstancePortEvent event) {
1039 InstancePort instPort = event.subject();
1040 return mastershipService.isLocalMaster(instPort.deviceId());
1041 }
1042
1043 @Override
1044 public void event(InstancePortEvent event) {
1045 InstancePort instPort = event.subject();
1046 switch (event.type()) {
1047 case OPENSTACK_INSTANCE_PORT_UPDATED:
1048 case OPENSTACK_INSTANCE_PORT_DETECTED:
1049 eventExecutor.execute(() -> {
1050 log.info("RoutingHandler: Instance port detected MAC:{} IP:{}",
1051 instPort.macAddress(),
1052 instPort.ipAddress());
1053 instPortDetected(event.subject());
1054 });
1055 break;
1056 case OPENSTACK_INSTANCE_PORT_VANISHED:
1057 eventExecutor.execute(() -> {
1058 log.info("RoutingHandler: Instance port vanished MAC:{} IP:{}",
1059 instPort.macAddress(),
1060 instPort.ipAddress());
1061 instPortRemoved(event.subject());
1062 });
1063 break;
1064 default:
1065 break;
1066 }
1067 }
1068
1069 private void instPortDetected(InstancePort instPort) {
daniel park796c2eb2018-03-22 17:01:51 +09001070 if (osNetworkAdminService.network(instPort.networkId()).getNetworkType() == NetworkType.FLAT) {
1071 return;
1072 }
Daniel Parkc64b4c62018-05-09 18:13:39 +09001073
1074 if (useStatefulSnat) {
1075 osNodeService.completeNodes(GATEWAY)
1076 .forEach(gwNode -> setRulesForSnatIngressRule(
1077 gwNode.intgBridge(),
1078 Long.parseLong(osNetworkAdminService
1079 .network(instPort.networkId()).getProviderSegID()),
1080 IpPrefix.valueOf(instPort.ipAddress(), 32),
1081 instPort.deviceId(), true));
1082 }
sangho072c4dd2017-05-17 10:45:21 +09001083 }
1084
1085 private void instPortRemoved(InstancePort instPort) {
daniel park796c2eb2018-03-22 17:01:51 +09001086 if (osNetworkAdminService.network(instPort.networkId()).getNetworkType() == NetworkType.FLAT) {
1087 return;
1088 }
Daniel Parkc64b4c62018-05-09 18:13:39 +09001089
1090 if (useStatefulSnat) {
1091 osNodeService.completeNodes(GATEWAY)
1092 .forEach(gwNode -> setRulesForSnatIngressRule(
1093 gwNode.intgBridge(),
1094 Long.parseLong(osNetworkAdminService
1095 .network(instPort.networkId()).getProviderSegID()),
1096 IpPrefix.valueOf(instPort.ipAddress(), 32),
1097 instPort.deviceId(), false));
1098 }
sangho072c4dd2017-05-17 10:45:21 +09001099 }
1100 }
Hyunsun Moon44aac662017-02-18 02:07:01 +09001101}