blob: 18c6d7c4199b0ff10b2f99f5f10a29a5925fb7c0 [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;
Hyunsun Moon0d457362017-06-27 17:19:41 +090062import org.onosproject.openstacknode.api.OpenstackNode;
63import org.onosproject.openstacknode.api.OpenstackNode.NetworkMode;
64import org.onosproject.openstacknode.api.OpenstackNodeEvent;
65import org.onosproject.openstacknode.api.OpenstackNodeListener;
66import org.onosproject.openstacknode.api.OpenstackNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090067import org.openstack4j.model.network.ExternalGateway;
68import org.openstack4j.model.network.Network;
daniel parkee8700b2017-05-11 15:50:03 +090069import org.openstack4j.model.network.NetworkType;
Hyunsun Moon44aac662017-02-18 02:07:01 +090070import org.openstack4j.model.network.Router;
71import org.openstack4j.model.network.RouterInterface;
72import org.openstack4j.model.network.Subnet;
sanghoe765ce22017-06-23 17:54:57 +090073import org.osgi.service.component.ComponentContext;
Hyunsun Moon44aac662017-02-18 02:07:01 +090074import org.slf4j.Logger;
75import org.slf4j.LoggerFactory;
76
sanghoe765ce22017-06-23 17:54:57 +090077import java.util.Dictionary;
Hyunsun Moon44aac662017-02-18 02:07:01 +090078import java.util.Objects;
sangho072c4dd2017-05-17 10:45:21 +090079import java.util.Optional;
Hyunsun Moon44aac662017-02-18 02:07:01 +090080import java.util.Set;
81import java.util.concurrent.ExecutorService;
82import java.util.stream.Collectors;
83
84import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
85import static org.onlab.util.Tools.groupedThreads;
sangho072c4dd2017-05-17 10:45:21 +090086import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_EXTERNAL_ROUTER_MAC;
87import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_GATEWAY_MAC;
88import static org.onosproject.openstacknetworking.api.Constants.FORWARDING_TABLE;
89import 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;
98import static org.onosproject.openstacknetworking.impl.RulePopulatorUtil.buildExtension;
Hyunsun Moon0d457362017-06-27 17:19:41 +090099import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
100import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900101
102/**
103 * Handles OpenStack router events.
104 */
105@Component(immediate = true)
106public class OpenstackRoutingHandler {
107
108 private final Logger log = LoggerFactory.getLogger(getClass());
109
110 private static final String MSG_ENABLED = "Enabled ";
111 private static final String MSG_DISABLED = "Disabled ";
daniel parkee8700b2017-05-11 15:50:03 +0900112 private static final String ERR_UNSUPPORTED_NET_TYPE = "Unsupported network type";
sanghoe765ce22017-06-23 17:54:57 +0900113 private static final boolean USE_STATEFUL_SNAT = false;
114
115 @Property(name = "useStatefulSnat", boolValue = USE_STATEFUL_SNAT,
116 label = "Use Stateful SNAT for source NATing")
117 private boolean useStatefulSnat = USE_STATEFUL_SNAT;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900118
119 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
120 protected CoreService coreService;
121
122 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
123 protected LeadershipService leadershipService;
124
125 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
126 protected ClusterService clusterService;
127
128 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900129 protected OpenstackNodeService osNodeService;
130
131 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
daniel park32b42202018-03-14 16:53:44 +0900132 protected OpenstackNetworkAdminService osNetworkAdminService;
133
134 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900135 protected OpenstackRouterService osRouterService;
136
daniel parkee8700b2017-05-11 15:50:03 +0900137 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho072c4dd2017-05-17 10:45:21 +0900138 protected InstancePortService instancePortService;
139
140 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
141 protected DeviceService deviceService;
142
143 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sanghodc375372017-06-08 10:41:30 +0900144 protected OpenstackFlowRuleService osFlowRuleService;
145
sangho072c4dd2017-05-17 10:45:21 +0900146 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
147 protected MastershipService mastershipService;
148
149 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
150 protected DriverService driverService;
151
sanghoe765ce22017-06-23 17:54:57 +0900152 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
153 protected ComponentConfigService configService;
154
Hyunsun Moon44aac662017-02-18 02:07:01 +0900155 private final ExecutorService eventExecutor = newSingleThreadScheduledExecutor(
156 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
157 private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
158 private final OpenstackRouterListener osRouterListener = new InternalRouterEventListener();
sangho072c4dd2017-05-17 10:45:21 +0900159 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900160
161 private ApplicationId appId;
162 private NodeId localNodeId;
163
164 @Activate
165 protected void activate() {
166 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
167 localNodeId = clusterService.getLocalNode().id();
168 leadershipService.runForLeadership(appId.name());
169 osNodeService.addListener(osNodeListener);
170 osRouterService.addListener(osRouterListener);
sangho072c4dd2017-05-17 10:45:21 +0900171 instancePortService.addListener(instancePortListener);
sanghoe765ce22017-06-23 17:54:57 +0900172 configService.registerProperties(getClass());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900173
174 log.info("Started");
175 }
176
177 @Deactivate
178 protected void deactivate() {
179 osRouterService.removeListener(osRouterListener);
180 osNodeService.removeListener(osNodeListener);
sangho072c4dd2017-05-17 10:45:21 +0900181 instancePortService.removeListener(instancePortListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900182 leadershipService.withdraw(appId.name());
sanghoe765ce22017-06-23 17:54:57 +0900183 configService.unregisterProperties(getClass(), false);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900184 eventExecutor.shutdown();
185
186 log.info("Stopped");
187 }
188
sanghoe765ce22017-06-23 17:54:57 +0900189 @Modified
190 protected void modified(ComponentContext context) {
191 Dictionary<?, ?> properties = context.getProperties();
192 Boolean flag;
193
194 flag = Tools.isPropertyEnabled(properties, "useStatefulSnat");
195 if (flag == null) {
196 log.info("useStatefulSnat is not configured, " +
197 "using current value of {}", useStatefulSnat);
198 } else {
199 useStatefulSnat = flag;
200 log.info("Configured. useStatefulSnat is {}",
201 useStatefulSnat ? "enabled" : "disabled");
202 }
203
204 resetSnatRules();
205 }
206
Hyunsun Moon44aac662017-02-18 02:07:01 +0900207 private void routerUpdated(Router osRouter) {
208 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
Frank Wang245a6822017-06-14 09:51:35 +0800209 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
Jian Liedc8b762018-03-22 15:42:00 +0900210 Network network = osNetworkAdminService.network(osNetworkAdminService.subnet(iface.getSubnetId())
Frank Wang245a6822017-06-14 09:51:35 +0800211 .getNetworkId());
212 setRouterAdminRules(network.getProviderSegID(), network.getNetworkType(), !osRouter.isAdminStateUp());
213 });
214
daniel park576969a2018-03-09 07:07:41 +0900215
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()
515 .setOutput(PortNumber.CONTROLLER)
516 .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))
sanghodc375372017-06-08 10:41:30 +0900544 .transition(FORWARDING_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))
sanghodc375372017-06-08 10:41:30 +0900565 .transition(FORWARDING_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))
sanghodc375372017-06-08 10:41:30 +0900587 .transition(FORWARDING_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))
sanghodc375372017-06-08 10:41:30 +0900608 .transition(FORWARDING_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
657 treatment = DefaultTrafficTreatment.builder()
daniel parkb5817102018-02-15 00:18:51 +0900658 .extension(buildExtension(
659 deviceService,
660 osNode.intgBridge(),
661 sourceNatGateway.dataIp().getIp4Address()),
662 osNode.intgBridge())
663 .setOutput(osNode.tunnelPortNum())
Hyunsun Moon44aac662017-02-18 02:07:01 +0900664 .build();
665
sanghodc375372017-06-08 10:41:30 +0900666 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900667 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900668 osNode.intgBridge(),
daniel parkee8700b2017-05-11 15:50:03 +0900669 sBuilder.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900670 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900671 PRIORITY_EXTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900672 ROUTING_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900673 install);
674 }
675
sangho072c4dd2017-05-17 10:45:21 +0900676 private void setRulesForSnatIngressRule(DeviceId deviceId, Long vni, IpPrefix destVmIp,
677 DeviceId dstDeviceId, boolean install) {
678
679 TrafficSelector selector = DefaultTrafficSelector.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900680 .matchEthType(Ethernet.TYPE_IPV4)
sangho072c4dd2017-05-17 10:45:21 +0900681 .matchIPDst(destVmIp)
682 .build();
Hyunsun Moon0d457362017-06-27 17:19:41 +0900683
sangho072c4dd2017-05-17 10:45:21 +0900684 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
685 .setTunnelId(vni)
686 .extension(buildExtension(
687 deviceService,
688 deviceId,
689 osNodeService.node(dstDeviceId).dataIp().getIp4Address()),
690 deviceId)
691 .setOutput(osNodeService.node(deviceId).tunnelPortNum())
692 .build();
daniel parkee8700b2017-05-11 15:50:03 +0900693
sanghodc375372017-06-08 10:41:30 +0900694 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900695 appId,
sangho072c4dd2017-05-17 10:45:21 +0900696 deviceId,
697 selector,
698 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900699 PRIORITY_EXTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900700 Constants.GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900701 install);
702 }
703
daniel parkb5817102018-02-15 00:18:51 +0900704 private void setRulesToGatewayWithDstIp(OpenstackNode osNode, OpenstackNode sourceNatGateway,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900705 String segmentId, IpAddress dstIp,
706 NetworkMode networkMode, boolean install) {
daniel parkee8700b2017-05-11 15:50:03 +0900707 TrafficSelector selector;
708 if (networkMode.equals(NetworkMode.VXLAN)) {
709 selector = DefaultTrafficSelector.builder()
710 .matchEthType(Ethernet.TYPE_IPV4)
711 .matchTunnelId(Long.valueOf(segmentId))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900712 .matchIPDst(dstIp.getIp4Address().toIpPrefix())
daniel parkee8700b2017-05-11 15:50:03 +0900713 .build();
714 } else {
715 selector = DefaultTrafficSelector.builder()
716 .matchEthType(Ethernet.TYPE_IPV4)
717 .matchVlanId(VlanId.vlanId(segmentId))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900718 .matchIPDst(dstIp.getIp4Address().toIpPrefix())
daniel parkee8700b2017-05-11 15:50:03 +0900719 .build();
720 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900721
722 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
daniel parkb5817102018-02-15 00:18:51 +0900723 .extension(buildExtension(
724 deviceService,
725 osNode.intgBridge(),
726 sourceNatGateway.dataIp().getIp4Address()),
727 osNode.intgBridge())
728 .setOutput(osNode.tunnelPortNum())
Hyunsun Moon44aac662017-02-18 02:07:01 +0900729 .build();
730
sanghodc375372017-06-08 10:41:30 +0900731 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900732 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900733 osNode.intgBridge(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900734 selector,
735 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900736 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900737 ROUTING_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900738 install);
739 }
740
sangho072c4dd2017-05-17 10:45:21 +0900741 private void setOvsNatIngressRule(DeviceId deviceId, IpPrefix cidr, MacAddress dstMac, boolean install) {
742
743 TrafficSelector selector = DefaultTrafficSelector.builder()
744 .matchEthType(Ethernet.TYPE_IPV4)
745 .matchIPDst(cidr)
746 .build();
747
Jian Liedc8b762018-03-22 15:42:00 +0900748 ExtensionTreatment natTreatment = RulePopulatorUtil
749 .niciraConnTrackTreatmentBuilder(driverService, deviceId)
sangho072c4dd2017-05-17 10:45:21 +0900750 .commit(false)
751 .natAction(true)
752 .table((short) 0)
753 .build();
754
755 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
756 .setEthDst(dstMac)
757 .extension(natTreatment, deviceId)
758 .build();
759
760 osFlowRuleService.setRule(
761 appId,
762 deviceId,
763 selector,
764 treatment,
sanghoe765ce22017-06-23 17:54:57 +0900765 PRIORITY_STATEFUL_SNAT_RULE,
sangho072c4dd2017-05-17 10:45:21 +0900766 GW_COMMON_TABLE,
767 install);
768 }
769
770 private void setOvsNatEgressRule(DeviceId deviceId, IpAddress natAddress, long vni, PortNumber output,
771 boolean install) {
772
773 TrafficSelector selector = DefaultTrafficSelector.builder()
774 .matchEthType(Ethernet.TYPE_IPV4)
775 .matchEthDst(DEFAULT_GATEWAY_MAC)
776 .matchTunnelId(vni)
777 .build();
778
Jian Liedc8b762018-03-22 15:42:00 +0900779 ExtensionTreatment natTreatment = RulePopulatorUtil
780 .niciraConnTrackTreatmentBuilder(driverService, deviceId)
sangho072c4dd2017-05-17 10:45:21 +0900781 .commit(true)
782 .natAction(true)
783 .natIp(natAddress)
784 .build();
785
786 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
787 .extension(natTreatment, deviceId)
788 .setEthDst(DEFAULT_EXTERNAL_ROUTER_MAC)
789 .setEthSrc(DEFAULT_GATEWAY_MAC)
790 .setOutput(output)
791 .build();
792
793 osFlowRuleService.setRule(
794 appId,
795 deviceId,
796 selector,
797 treatment,
sanghoe765ce22017-06-23 17:54:57 +0900798 PRIORITY_STATEFUL_SNAT_RULE,
sangho072c4dd2017-05-17 10:45:21 +0900799 GW_COMMON_TABLE,
800 install);
801 }
802
sanghoe765ce22017-06-23 17:54:57 +0900803 private void setRulesToController(DeviceId deviceId, String segmentId, IpPrefix srcSubnet,
804 NetworkType networkType, boolean install) {
805 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
806 .matchEthType(Ethernet.TYPE_IPV4)
807 .matchIPSrc(srcSubnet);
808
809 switch (networkType) {
810 case VXLAN:
811 sBuilder.matchTunnelId(Long.parseLong(segmentId))
812 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
813 break;
814 case VLAN:
815 sBuilder.matchVlanId(VlanId.vlanId(segmentId))
816 .matchEthDst(osNodeService.node(deviceId).vlanPortMac());
817 break;
818 default:
Jian Li71670d12018-03-02 21:31:07 +0900819 final String error = String.format("%s %s",
820 ERR_UNSUPPORTED_NET_TYPE,
sanghoe765ce22017-06-23 17:54:57 +0900821 networkType.toString());
822 throw new IllegalStateException(error);
823 }
824
825 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
826 .setEthDst(Constants.DEFAULT_GATEWAY_MAC);
827
828 if (networkType.equals(NetworkType.VLAN)) {
829 tBuilder.popVlan();
830 }
831
832 tBuilder.setOutput(PortNumber.CONTROLLER);
833
834 osFlowRuleService.setRule(
835 appId,
836 deviceId,
837 sBuilder.build(),
838 tBuilder.build(),
839 PRIORITY_EXTERNAL_ROUTING_RULE,
840 GW_COMMON_TABLE,
841 install);
842
843
844 // Sends ICMP response to controller for SNATing ingress traffic
845 TrafficSelector selector = DefaultTrafficSelector.builder()
846 .matchEthType(Ethernet.TYPE_IPV4)
847 .matchIPProtocol(IPv4.PROTOCOL_ICMP)
848 .matchIcmpType(ICMP.TYPE_ECHO_REPLY)
849 .build();
850
851 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
852 .setOutput(PortNumber.CONTROLLER)
853 .build();
854
855 osFlowRuleService.setRule(
856 appId,
857 deviceId,
858 selector,
859 treatment,
860 PRIORITY_INTERNAL_ROUTING_RULE,
861 GW_COMMON_TABLE,
862 install);
863 }
sangho072c4dd2017-05-17 10:45:21 +0900864
Frank Wang245a6822017-06-14 09:51:35 +0800865 private void setRouterAdminRules(String segmentId, NetworkType networkType, boolean install) {
866 TrafficTreatment treatment;
867 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
868 .matchEthType(Ethernet.TYPE_IPV4);
869
870 switch (networkType) {
871 case VXLAN:
872 sBuilder.matchTunnelId(Long.parseLong(segmentId));
873 break;
874 case VLAN:
875 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
876 break;
877 default:
Jian Li71670d12018-03-02 21:31:07 +0900878 final String error = String.format("%s %s",
879 ERR_UNSUPPORTED_NET_TYPE,
Frank Wang245a6822017-06-14 09:51:35 +0800880 networkType.toString());
881 throw new IllegalStateException(error);
882 }
883
884 treatment = DefaultTrafficTreatment.builder()
885 .drop()
886 .build();
887
888 osNodeService.completeNodes().stream()
889 .filter(osNode -> osNode.type() == COMPUTE)
890 .forEach(osNode -> {
891 osFlowRuleService.setRule(
892 appId,
893 osNode.intgBridge(),
894 sBuilder.build(),
895 treatment,
896 PRIORITY_ADMIN_RULE,
897 ROUTING_TABLE,
898 install);
899 });
900 }
901
Hyunsun Moon44aac662017-02-18 02:07:01 +0900902 private class InternalRouterEventListener implements OpenstackRouterListener {
903
904 @Override
905 public boolean isRelevant(OpenstackRouterEvent event) {
906 // do not allow to proceed without leadership
907 NodeId leader = leadershipService.getLeader(appId.name());
908 return Objects.equals(localNodeId, leader);
909 }
910
911 // FIXME only one leader in the cluster should process
912 @Override
913 public void event(OpenstackRouterEvent event) {
914 switch (event.type()) {
915 case OPENSTACK_ROUTER_CREATED:
916 log.debug("Router(name:{}, ID:{}) is created",
917 event.subject().getName(),
918 event.subject().getId());
919 eventExecutor.execute(() -> routerUpdated(event.subject()));
920 break;
921 case OPENSTACK_ROUTER_UPDATED:
922 log.debug("Router(name:{}, ID:{}) is updated",
923 event.subject().getName(),
924 event.subject().getId());
925 eventExecutor.execute(() -> routerUpdated(event.subject()));
926 break;
927 case OPENSTACK_ROUTER_REMOVED:
928 log.debug("Router(name:{}, ID:{}) is removed",
929 event.subject().getName(),
930 event.subject().getId());
Frank Wang245a6822017-06-14 09:51:35 +0800931 eventExecutor.execute(() -> routerRemove(event.subject()));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900932 break;
933 case OPENSTACK_ROUTER_INTERFACE_ADDED:
934 log.debug("Router interface {} added to router {}",
935 event.routerIface().getPortId(),
936 event.routerIface().getId());
937 eventExecutor.execute(() -> routerIfaceAdded(
938 event.subject(),
939 event.routerIface()));
940 break;
941 case OPENSTACK_ROUTER_INTERFACE_UPDATED:
942 log.debug("Router interface {} on {} updated",
943 event.routerIface().getPortId(),
944 event.routerIface().getId());
945 break;
946 case OPENSTACK_ROUTER_INTERFACE_REMOVED:
947 log.debug("Router interface {} removed from router {}",
948 event.routerIface().getPortId(),
949 event.routerIface().getId());
950 eventExecutor.execute(() -> routerIfaceRemoved(
951 event.subject(),
952 event.routerIface()));
953 break;
954 case OPENSTACK_ROUTER_GATEWAY_ADDED:
daniel parkb5817102018-02-15 00:18:51 +0900955 log.debug("Router external gateway {} added", event.externalGateway().getNetworkId());
Ray Milkey08932a72018-02-20 15:34:38 -0800956 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900957 case OPENSTACK_ROUTER_GATEWAY_REMOVED:
daniel parkb5817102018-02-15 00:18:51 +0900958 log.debug("Router external gateway {} removed", event.externalGateway().getNetworkId());
Ray Milkey08932a72018-02-20 15:34:38 -0800959 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900960 case OPENSTACK_FLOATING_IP_CREATED:
961 case OPENSTACK_FLOATING_IP_UPDATED:
962 case OPENSTACK_FLOATING_IP_REMOVED:
963 case OPENSTACK_FLOATING_IP_ASSOCIATED:
964 case OPENSTACK_FLOATING_IP_DISASSOCIATED:
965 default:
966 // do nothing for the other events
967 break;
968 }
969 }
970 }
971
972 private class InternalNodeEventListener implements OpenstackNodeListener {
973
974 @Override
975 public boolean isRelevant(OpenstackNodeEvent event) {
976 // do not allow to proceed without leadership
977 NodeId leader = leadershipService.getLeader(appId.name());
978 return Objects.equals(localNodeId, leader);
979 }
980
981 @Override
982 public void event(OpenstackNodeEvent event) {
983 OpenstackNode osNode = event.subject();
984
985 switch (event.type()) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900986 case OPENSTACK_NODE_COMPLETE:
987 case OPENSTACK_NODE_INCOMPLETE:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900988 eventExecutor.execute(() -> {
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900989 log.info("Reconfigure routers for {}", osNode.hostname());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900990 reconfigureRouters();
991 });
992 break;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900993 case OPENSTACK_NODE_CREATED:
994 case OPENSTACK_NODE_UPDATED:
995 case OPENSTACK_NODE_REMOVED:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900996 default:
997 break;
998 }
999 }
1000
1001 private void reconfigureRouters() {
1002 osRouterService.routers().forEach(osRouter -> {
1003 routerUpdated(osRouter);
1004 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
1005 routerIfaceAdded(osRouter, iface);
1006 });
1007 });
1008 }
1009 }
sangho072c4dd2017-05-17 10:45:21 +09001010
1011 private class InternalInstancePortListener implements InstancePortListener {
1012
1013 @Override
1014 public boolean isRelevant(InstancePortEvent event) {
1015 InstancePort instPort = event.subject();
1016 return mastershipService.isLocalMaster(instPort.deviceId());
1017 }
1018
1019 @Override
1020 public void event(InstancePortEvent event) {
1021 InstancePort instPort = event.subject();
1022 switch (event.type()) {
1023 case OPENSTACK_INSTANCE_PORT_UPDATED:
1024 case OPENSTACK_INSTANCE_PORT_DETECTED:
1025 eventExecutor.execute(() -> {
1026 log.info("RoutingHandler: Instance port detected MAC:{} IP:{}",
1027 instPort.macAddress(),
1028 instPort.ipAddress());
1029 instPortDetected(event.subject());
1030 });
1031 break;
1032 case OPENSTACK_INSTANCE_PORT_VANISHED:
1033 eventExecutor.execute(() -> {
1034 log.info("RoutingHandler: Instance port vanished MAC:{} IP:{}",
1035 instPort.macAddress(),
1036 instPort.ipAddress());
1037 instPortRemoved(event.subject());
1038 });
1039 break;
1040 default:
1041 break;
1042 }
1043 }
1044
1045 private void instPortDetected(InstancePort instPort) {
daniel park796c2eb2018-03-22 17:01:51 +09001046 if (osNetworkAdminService.network(instPort.networkId()).getNetworkType() == NetworkType.FLAT) {
1047 return;
1048 }
sangho072c4dd2017-05-17 10:45:21 +09001049 osNodeService.completeNodes(GATEWAY)
Jian Liedc8b762018-03-22 15:42:00 +09001050 .forEach(gwNode -> setRulesForSnatIngressRule(
1051 gwNode.intgBridge(),
1052 Long.parseLong(osNetworkAdminService
1053 .network(instPort.networkId()).getProviderSegID()),
1054 IpPrefix.valueOf(instPort.ipAddress(), 32),
1055 instPort.deviceId(), true));
sangho072c4dd2017-05-17 10:45:21 +09001056 }
1057
1058 private void instPortRemoved(InstancePort instPort) {
daniel park796c2eb2018-03-22 17:01:51 +09001059 if (osNetworkAdminService.network(instPort.networkId()).getNetworkType() == NetworkType.FLAT) {
1060 return;
1061 }
sangho072c4dd2017-05-17 10:45:21 +09001062 osNodeService.completeNodes(GATEWAY)
Jian Liedc8b762018-03-22 15:42:00 +09001063 .forEach(gwNode -> setRulesForSnatIngressRule(
1064 gwNode.intgBridge(),
1065 Long.parseLong(osNetworkAdminService
1066 .network(instPort.networkId()).getProviderSegID()),
1067 IpPrefix.valueOf(instPort.ipAddress(), 32),
1068 instPort.deviceId(), false));
sangho072c4dd2017-05-17 10:45:21 +09001069 }
1070 }
Hyunsun Moon44aac662017-02-18 02:07:01 +09001071}