blob: b2d90a4cffc427f1c11be642b8c940565cbb001b [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.OpenstackNetworkService;
60import org.onosproject.openstacknetworking.api.OpenstackRouterEvent;
61import org.onosproject.openstacknetworking.api.OpenstackRouterListener;
62import org.onosproject.openstacknetworking.api.OpenstackRouterService;
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;
99import static org.onosproject.openstacknetworking.impl.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)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900133 protected OpenstackNetworkService osNetworkService;
134
135 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
daniel park32b42202018-03-14 16:53:44 +0900136 protected OpenstackNetworkAdminService osNetworkAdminService;
137
138 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900139 protected OpenstackRouterService osRouterService;
140
daniel parkee8700b2017-05-11 15:50:03 +0900141 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho072c4dd2017-05-17 10:45:21 +0900142 protected InstancePortService instancePortService;
143
144 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
145 protected DeviceService deviceService;
146
147 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sanghodc375372017-06-08 10:41:30 +0900148 protected OpenstackFlowRuleService osFlowRuleService;
149
sangho072c4dd2017-05-17 10:45:21 +0900150 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
151 protected MastershipService mastershipService;
152
153 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
154 protected DriverService driverService;
155
sanghoe765ce22017-06-23 17:54:57 +0900156 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
157 protected ComponentConfigService configService;
158
Hyunsun Moon44aac662017-02-18 02:07:01 +0900159 private final ExecutorService eventExecutor = newSingleThreadScheduledExecutor(
160 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
161 private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
162 private final OpenstackRouterListener osRouterListener = new InternalRouterEventListener();
sangho072c4dd2017-05-17 10:45:21 +0900163 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900164
165 private ApplicationId appId;
166 private NodeId localNodeId;
167
168 @Activate
169 protected void activate() {
170 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
171 localNodeId = clusterService.getLocalNode().id();
172 leadershipService.runForLeadership(appId.name());
173 osNodeService.addListener(osNodeListener);
174 osRouterService.addListener(osRouterListener);
sangho072c4dd2017-05-17 10:45:21 +0900175 instancePortService.addListener(instancePortListener);
sanghoe765ce22017-06-23 17:54:57 +0900176 configService.registerProperties(getClass());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900177
178 log.info("Started");
179 }
180
181 @Deactivate
182 protected void deactivate() {
183 osRouterService.removeListener(osRouterListener);
184 osNodeService.removeListener(osNodeListener);
sangho072c4dd2017-05-17 10:45:21 +0900185 instancePortService.removeListener(instancePortListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900186 leadershipService.withdraw(appId.name());
sanghoe765ce22017-06-23 17:54:57 +0900187 configService.unregisterProperties(getClass(), false);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900188 eventExecutor.shutdown();
189
190 log.info("Stopped");
191 }
192
sanghoe765ce22017-06-23 17:54:57 +0900193 @Modified
194 protected void modified(ComponentContext context) {
195 Dictionary<?, ?> properties = context.getProperties();
196 Boolean flag;
197
198 flag = Tools.isPropertyEnabled(properties, "useStatefulSnat");
199 if (flag == null) {
200 log.info("useStatefulSnat is not configured, " +
201 "using current value of {}", useStatefulSnat);
202 } else {
203 useStatefulSnat = flag;
204 log.info("Configured. useStatefulSnat is {}",
205 useStatefulSnat ? "enabled" : "disabled");
206 }
207
208 resetSnatRules();
209 }
210
Hyunsun Moon44aac662017-02-18 02:07:01 +0900211 private void routerUpdated(Router osRouter) {
212 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
Frank Wang245a6822017-06-14 09:51:35 +0800213 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
214 Network network = osNetworkService.network(osNetworkService.subnet(iface.getSubnetId())
215 .getNetworkId());
216 setRouterAdminRules(network.getProviderSegID(), network.getNetworkType(), !osRouter.isAdminStateUp());
217 });
218
daniel park576969a2018-03-09 07:07:41 +0900219
220 ExternalPeerRouter externalPeerRouter = osNetworkService.externalPeerRouter(exGateway);
221 VlanId vlanId = externalPeerRouter == null ? VlanId.NONE : externalPeerRouter.externalPeerRouterVlanId();
222
Hyunsun Moon44aac662017-02-18 02:07:01 +0900223 if (exGateway == null) {
daniel park32b42202018-03-14 16:53:44 +0900224 osNetworkAdminService.deleteExternalPeerRouter(exGateway);
daniel park576969a2018-03-09 07:07:41 +0900225 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> setSourceNat(iface, false));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900226 } else {
daniel park32b42202018-03-14 16:53:44 +0900227 osNetworkAdminService.deriveExternalPeerRouterMac(exGateway, osRouter, vlanId);
daniel park576969a2018-03-09 07:07:41 +0900228 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface ->
229 setSourceNat(iface, exGateway.isEnableSnat()));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900230 }
231 }
232
Frank Wang245a6822017-06-14 09:51:35 +0800233 private void routerRemove(Router osRouter) {
234 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
235 Network network = osNetworkService.network(osNetworkService.subnet(iface.getSubnetId())
236 .getNetworkId());
237 setRouterAdminRules(network.getProviderSegID(), network.getNetworkType(), false);
238 });
239 }
240
Hyunsun Moon44aac662017-02-18 02:07:01 +0900241 private void routerIfaceAdded(Router osRouter, RouterInterface osRouterIface) {
242 Subnet osSubnet = osNetworkService.subnet(osRouterIface.getSubnetId());
243 if (osSubnet == null) {
244 final String error = String.format(
Jian Li71670d12018-03-02 21:31:07 +0900245 "Failed to set flows for router %s: subnet %s does not exist",
Hyunsun Moon44aac662017-02-18 02:07:01 +0900246 osRouterIface.getId(),
247 osRouterIface.getSubnetId());
248 throw new IllegalStateException(error);
249 }
Frank Wang245a6822017-06-14 09:51:35 +0800250
251 if (!osRouter.isAdminStateUp()) {
252 Network network = osNetworkService.network(osSubnet.getNetworkId());
253 setRouterAdminRules(network.getProviderSegID(), network.getNetworkType(), true);
254 }
255
Hyunsun Moon44aac662017-02-18 02:07:01 +0900256 setInternalRoutes(osRouter, osSubnet, true);
257 setGatewayIcmp(osSubnet, true);
258 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
259 if (exGateway != null && exGateway.isEnableSnat()) {
daniel park576969a2018-03-09 07:07:41 +0900260 setSourceNat(osRouterIface, true);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900261 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900262 log.info("Connected subnet({}) to {}", osSubnet.getCidr(), osRouter.getName());
263 }
264
265 private void routerIfaceRemoved(Router osRouter, RouterInterface osRouterIface) {
266 Subnet osSubnet = osNetworkService.subnet(osRouterIface.getSubnetId());
267 if (osSubnet == null) {
268 final String error = String.format(
Jian Li71670d12018-03-02 21:31:07 +0900269 "Failed to set flows for router %s: subnet %s does not exist",
Hyunsun Moon44aac662017-02-18 02:07:01 +0900270 osRouterIface.getId(),
271 osRouterIface.getSubnetId());
272 throw new IllegalStateException(error);
273 }
274
Frank Wang245a6822017-06-14 09:51:35 +0800275 if (!osRouter.isAdminStateUp()) {
276 Network network = osNetworkService.network(osSubnet.getNetworkId());
277 setRouterAdminRules(network.getProviderSegID(), network.getNetworkType(), false);
278 }
279
Hyunsun Moon44aac662017-02-18 02:07:01 +0900280 setInternalRoutes(osRouter, osSubnet, false);
281 setGatewayIcmp(osSubnet, false);
282 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
283 if (exGateway != null && exGateway.isEnableSnat()) {
daniel park576969a2018-03-09 07:07:41 +0900284 setSourceNat(osRouterIface, false);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900285 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900286 log.info("Disconnected subnet({}) from {}", osSubnet.getCidr(), osRouter.getName());
287 }
288
daniel park576969a2018-03-09 07:07:41 +0900289 private void setSourceNat(RouterInterface routerIface, boolean install) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900290 Subnet osSubnet = osNetworkService.subnet(routerIface.getSubnetId());
291 Network osNet = osNetworkService.network(osSubnet.getNetworkId());
292
Hyunsun Moon0d457362017-06-27 17:19:41 +0900293 osNodeService.completeNodes(COMPUTE).forEach(cNode -> {
294 setRulesToGateway(cNode, osNet.getProviderSegID(),
295 IpPrefix.valueOf(osSubnet.getCidr()), osNet.getNetworkType(),
296 install);
297 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900298
sanghoe765ce22017-06-23 17:54:57 +0900299 if (useStatefulSnat) {
300 setStatefulSnatRules(routerIface, install);
301 } else {
302 setReactiveSnatRules(routerIface, install);
303 }
304
305 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
306 log.info(updateStr + "external access for subnet({})", osSubnet.getCidr());
307 }
308
309 private void setStatefulSnatRules(RouterInterface routerIface, boolean install) {
310 Subnet osSubnet = osNetworkService.subnet(routerIface.getSubnetId());
311 Network osNet = osNetworkService.network(osSubnet.getNetworkId());
312
daniel park796c2eb2018-03-22 17:01:51 +0900313 if (osNet.getNetworkType() == NetworkType.FLAT) {
314 return;
315 }
316
sanghoe765ce22017-06-23 17:54:57 +0900317 Optional<Router> osRouter = osRouterService.routers().stream()
318 .filter(router -> osRouterService.routerInterfaces(routerIface.getId()) != null)
319 .findAny();
320
321 if (!osRouter.isPresent()) {
322 log.error("Cannot find a router for router interface {} ", routerIface);
323 return;
324 }
325 IpAddress natAddress = getGatewayIpAddress(osRouter.get());
sangho072c4dd2017-05-17 10:45:21 +0900326 if (natAddress == null) {
327 return;
328 }
329 String netId = osNetworkService.subnet(routerIface.getSubnetId()).getNetworkId();
330
331 osNodeService.completeNodes(OpenstackNode.NodeType.GATEWAY)
332 .forEach(gwNode -> {
daniel park576969a2018-03-09 07:07:41 +0900333 instancePortService.instancePorts(netId)
334 .forEach(port -> setRulesForSnatIngressRule(gwNode.intgBridge(),
sangho072c4dd2017-05-17 10:45:21 +0900335 Long.parseLong(osNet.getProviderSegID()),
336 IpPrefix.valueOf(port.ipAddress(), 32),
337 port.deviceId(),
338 install));
339
340 setOvsNatIngressRule(gwNode.intgBridge(),
341 IpPrefix.valueOf(natAddress, 32),
342 Constants.DEFAULT_EXTERNAL_ROUTER_MAC, install);
343 setOvsNatEgressRule(gwNode.intgBridge(),
344 natAddress, Long.parseLong(osNet.getProviderSegID()),
345 gwNode.patchPortNum(), install);
346 });
sanghoe765ce22017-06-23 17:54:57 +0900347 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900348
sanghoe765ce22017-06-23 17:54:57 +0900349 private void setReactiveSnatRules(RouterInterface routerIface, boolean install) {
350 Subnet osSubnet = osNetworkService.subnet(routerIface.getSubnetId());
351 Network osNet = osNetworkService.network(osSubnet.getNetworkId());
352
353 osNodeService.completeNodes(GATEWAY)
354 .forEach(gwNode -> setRulesToController(
355 gwNode.intgBridge(),
356 osNet.getProviderSegID(),
357 IpPrefix.valueOf(osSubnet.getCidr()),
358 osNet.getNetworkType(),
359 install));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900360 }
361
sangho072c4dd2017-05-17 10:45:21 +0900362 private IpAddress getGatewayIpAddress(Router osRouter) {
363
364 String extNetId = osNetworkService.network(osRouter.getExternalGatewayInfo().getNetworkId()).getId();
365 Optional<Subnet> extSubnet = osNetworkService.subnets().stream()
366 .filter(subnet -> subnet.getNetworkId().equals(extNetId))
367 .findAny();
368
369 if (!extSubnet.isPresent()) {
370 log.error("Cannot find externel subnet for the router");
371 return null;
372 }
373
374 return IpAddress.valueOf(extSubnet.get().getGateway());
375 }
376
sanghoe765ce22017-06-23 17:54:57 +0900377 private void resetSnatRules() {
378 if (useStatefulSnat) {
379 osRouterService.routerInterfaces().forEach(
380 routerIface -> {
381 setReactiveSnatRules(routerIface, false);
382 setStatefulSnatRules(routerIface, true);
383 }
384 );
385 } else {
386 osRouterService.routerInterfaces().forEach(
387 routerIface -> {
388 setStatefulSnatRules(routerIface, false);
389 setReactiveSnatRules(routerIface, true);
390 }
391 );
392 }
393 }
394
Hyunsun Moon44aac662017-02-18 02:07:01 +0900395 private void setGatewayIcmp(Subnet osSubnet, boolean install) {
daniel parkb5817102018-02-15 00:18:51 +0900396 OpenstackNode sourceNatGateway = osNodeService.completeNodes(GATEWAY).stream().findFirst().orElse(null);
397
398 if (sourceNatGateway == null) {
399 return;
400 }
401
Hyunsun Moon44aac662017-02-18 02:07:01 +0900402 if (Strings.isNullOrEmpty(osSubnet.getGateway())) {
403 // do nothing if no gateway is set
404 return;
405 }
406
407 // take ICMP request to a subnet gateway through gateway node group
408 Network network = osNetworkService.network(osSubnet.getNetworkId());
daniel parkee8700b2017-05-11 15:50:03 +0900409 switch (network.getNetworkType()) {
410 case VXLAN:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900411 osNodeService.completeNodes(COMPUTE).stream()
412 .filter(cNode -> cNode.dataIp() != null)
413 .forEach(cNode -> setRulesToGatewayWithDstIp(
414 cNode,
daniel parkb5817102018-02-15 00:18:51 +0900415 sourceNatGateway,
daniel parkee8700b2017-05-11 15:50:03 +0900416 network.getProviderSegID(),
417 IpAddress.valueOf(osSubnet.getGateway()),
418 NetworkMode.VXLAN,
419 install));
420 break;
421 case VLAN:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900422 osNodeService.completeNodes(COMPUTE).stream()
423 .filter(cNode -> cNode.vlanPortNum() != null)
424 .forEach(cNode -> setRulesToGatewayWithDstIp(
425 cNode,
daniel parkb5817102018-02-15 00:18:51 +0900426 sourceNatGateway,
daniel parkee8700b2017-05-11 15:50:03 +0900427 network.getProviderSegID(),
428 IpAddress.valueOf(osSubnet.getGateway()),
429 NetworkMode.VLAN,
430 install));
431 break;
432 default:
Jian Li71670d12018-03-02 21:31:07 +0900433 final String error = String.format("%s %s",
434 ERR_UNSUPPORTED_NET_TYPE,
daniel parkee8700b2017-05-11 15:50:03 +0900435 network.getNetworkType().toString());
436 throw new IllegalStateException(error);
437 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900438
439 IpAddress gatewayIp = IpAddress.valueOf(osSubnet.getGateway());
daniel park576969a2018-03-09 07:07:41 +0900440 osNodeService.completeNodes(GATEWAY).forEach(gNode ->
Hyunsun Moon0d457362017-06-27 17:19:41 +0900441 setGatewayIcmpRule(
442 gatewayIp,
443 gNode.intgBridge(),
daniel park576969a2018-03-09 07:07:41 +0900444 install));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900445
446 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
447 log.debug(updateStr + "ICMP to {}", osSubnet.getGateway());
448 }
449
450 private void setInternalRoutes(Router osRouter, Subnet updatedSubnet, boolean install) {
daniel parkee8700b2017-05-11 15:50:03 +0900451 Network updatedNetwork = osNetworkService.network(updatedSubnet.getNetworkId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900452 Set<Subnet> routableSubnets = routableSubnets(osRouter, updatedSubnet.getId());
daniel parkee8700b2017-05-11 15:50:03 +0900453 String updatedSegmendId = getSegmentId(updatedSubnet);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900454
455 // installs rule from/to my subnet intentionally to fix ICMP failure
456 // to my subnet gateway if no external gateway added to the router
Hyunsun Moon0d457362017-06-27 17:19:41 +0900457 osNodeService.completeNodes(COMPUTE).forEach(cNode -> {
458 setInternalRouterRules(
459 cNode.intgBridge(),
460 updatedSegmendId,
461 updatedSegmendId,
462 IpPrefix.valueOf(updatedSubnet.getCidr()),
463 IpPrefix.valueOf(updatedSubnet.getCidr()),
464 updatedNetwork.getNetworkType(),
465 install
466 );
Hyunsun Moon44aac662017-02-18 02:07:01 +0900467
Hyunsun Moon0d457362017-06-27 17:19:41 +0900468 routableSubnets.forEach(subnet -> {
469 setInternalRouterRules(
470 cNode.intgBridge(),
471 updatedSegmendId,
472 getSegmentId(subnet),
473 IpPrefix.valueOf(updatedSubnet.getCidr()),
474 IpPrefix.valueOf(subnet.getCidr()),
475 updatedNetwork.getNetworkType(),
476 install
477 );
478 setInternalRouterRules(
479 cNode.intgBridge(),
480 getSegmentId(subnet),
481 updatedSegmendId,
482 IpPrefix.valueOf(subnet.getCidr()),
483 IpPrefix.valueOf(updatedSubnet.getCidr()),
484 updatedNetwork.getNetworkType(),
485 install
486 );
487 });
488 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900489
daniel parkee8700b2017-05-11 15:50:03 +0900490
Hyunsun Moon44aac662017-02-18 02:07:01 +0900491 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
492 routableSubnets.forEach(subnet -> log.debug(
493 updateStr + "route between subnet:{} and subnet:{}",
494 subnet.getCidr(),
495 updatedSubnet.getCidr()));
496 }
497
498 private Set<Subnet> routableSubnets(Router osRouter, String osSubnetId) {
499 Set<Subnet> osSubnets = osRouterService.routerInterfaces(osRouter.getId())
500 .stream()
501 .filter(iface -> !Objects.equals(iface.getSubnetId(), osSubnetId))
502 .map(iface -> osNetworkService.subnet(iface.getSubnetId()))
503 .collect(Collectors.toSet());
504 return ImmutableSet.copyOf(osSubnets);
505 }
506
daniel parkee8700b2017-05-11 15:50:03 +0900507 private String getSegmentId(Subnet osSubnet) {
508 return osNetworkService.network(osSubnet.getNetworkId()).getProviderSegID();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900509 }
510
511 private void setGatewayIcmpRule(IpAddress gatewayIp, DeviceId deviceId, boolean install) {
512 TrafficSelector selector = DefaultTrafficSelector.builder()
513 .matchEthType(Ethernet.TYPE_IPV4)
514 .matchIPProtocol(IPv4.PROTOCOL_ICMP)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900515 .matchIPDst(gatewayIp.getIp4Address().toIpPrefix())
Hyunsun Moon44aac662017-02-18 02:07:01 +0900516 .build();
517
518 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
519 .setOutput(PortNumber.CONTROLLER)
520 .build();
521
sanghodc375372017-06-08 10:41:30 +0900522 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900523 appId,
524 deviceId,
525 selector,
526 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900527 PRIORITY_ICMP_RULE,
sanghodc375372017-06-08 10:41:30 +0900528 Constants.GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900529 install);
530 }
531
daniel parkee8700b2017-05-11 15:50:03 +0900532 private void setInternalRouterRules(DeviceId deviceId, String srcSegmentId, String dstSegmentId,
533 IpPrefix srcSubnet, IpPrefix dstSubnet,
534 NetworkType networkType, boolean install) {
535 TrafficSelector selector;
536 TrafficTreatment treatment;
537 switch (networkType) {
538 case VXLAN:
539 selector = DefaultTrafficSelector.builder()
540 .matchEthType(Ethernet.TYPE_IPV4)
541 .matchTunnelId(Long.parseLong(srcSegmentId))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900542 .matchIPSrc(srcSubnet.getIp4Prefix())
543 .matchIPDst(dstSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900544 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900545
daniel parkee8700b2017-05-11 15:50:03 +0900546 treatment = DefaultTrafficTreatment.builder()
547 .setTunnelId(Long.parseLong(dstSegmentId))
sanghodc375372017-06-08 10:41:30 +0900548 .transition(FORWARDING_TABLE)
daniel parkee8700b2017-05-11 15:50:03 +0900549 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900550
sanghodc375372017-06-08 10:41:30 +0900551 osFlowRuleService.setRule(
daniel parkee8700b2017-05-11 15:50:03 +0900552 appId,
553 deviceId,
554 selector,
555 treatment,
daniel parkee8700b2017-05-11 15:50:03 +0900556 PRIORITY_INTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900557 ROUTING_TABLE,
daniel parkee8700b2017-05-11 15:50:03 +0900558 install);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900559
daniel parkee8700b2017-05-11 15:50:03 +0900560 selector = DefaultTrafficSelector.builder()
561 .matchEthType(Ethernet.TYPE_IPV4)
562 .matchTunnelId(Long.parseLong(dstSegmentId))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900563 .matchIPSrc(srcSubnet.getIp4Prefix())
564 .matchIPDst(dstSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900565 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900566
daniel parkee8700b2017-05-11 15:50:03 +0900567 treatment = DefaultTrafficTreatment.builder()
568 .setTunnelId(Long.parseLong(dstSegmentId))
sanghodc375372017-06-08 10:41:30 +0900569 .transition(FORWARDING_TABLE)
daniel parkee8700b2017-05-11 15:50:03 +0900570 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900571
sanghodc375372017-06-08 10:41:30 +0900572 osFlowRuleService.setRule(
daniel parkee8700b2017-05-11 15:50:03 +0900573 appId,
574 deviceId,
575 selector,
576 treatment,
daniel parkee8700b2017-05-11 15:50:03 +0900577 PRIORITY_INTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900578 ROUTING_TABLE,
daniel parkee8700b2017-05-11 15:50:03 +0900579 install);
580 break;
581 case VLAN:
582 selector = DefaultTrafficSelector.builder()
583 .matchEthType(Ethernet.TYPE_IPV4)
584 .matchVlanId(VlanId.vlanId(srcSegmentId))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900585 .matchIPSrc(srcSubnet.getIp4Prefix())
586 .matchIPDst(dstSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900587 .build();
588
589 treatment = DefaultTrafficTreatment.builder()
590 .setVlanId(VlanId.vlanId(dstSegmentId))
sanghodc375372017-06-08 10:41:30 +0900591 .transition(FORWARDING_TABLE)
daniel parkee8700b2017-05-11 15:50:03 +0900592 .build();
593
sanghodc375372017-06-08 10:41:30 +0900594 osFlowRuleService.setRule(
daniel parkee8700b2017-05-11 15:50:03 +0900595 appId,
596 deviceId,
597 selector,
598 treatment,
daniel parkee8700b2017-05-11 15:50:03 +0900599 PRIORITY_INTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900600 ROUTING_TABLE,
daniel parkee8700b2017-05-11 15:50:03 +0900601 install);
602
603 selector = DefaultTrafficSelector.builder()
604 .matchEthType(Ethernet.TYPE_IPV4)
605 .matchVlanId(VlanId.vlanId(dstSegmentId))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900606 .matchIPSrc(srcSubnet.getIp4Prefix())
607 .matchIPDst(dstSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900608 .build();
609
610 treatment = DefaultTrafficTreatment.builder()
611 .setVlanId(VlanId.vlanId(dstSegmentId))
sanghodc375372017-06-08 10:41:30 +0900612 .transition(FORWARDING_TABLE)
daniel parkee8700b2017-05-11 15:50:03 +0900613 .build();
614
sanghodc375372017-06-08 10:41:30 +0900615 osFlowRuleService.setRule(
daniel parkee8700b2017-05-11 15:50:03 +0900616 appId,
617 deviceId,
618 selector,
619 treatment,
daniel parkee8700b2017-05-11 15:50:03 +0900620 PRIORITY_INTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900621 ROUTING_TABLE,
daniel parkee8700b2017-05-11 15:50:03 +0900622 install);
623 break;
624 default:
Jian Li71670d12018-03-02 21:31:07 +0900625 final String error = String.format("%s %s",
626 ERR_UNSUPPORTED_NET_TYPE,
daniel parkee8700b2017-05-11 15:50:03 +0900627 networkType.toString());
628 throw new IllegalStateException(error);
629 }
630
Hyunsun Moon44aac662017-02-18 02:07:01 +0900631 }
632
Hyunsun Moon0d457362017-06-27 17:19:41 +0900633 private void setRulesToGateway(OpenstackNode osNode, String segmentId, IpPrefix srcSubnet,
daniel parkee8700b2017-05-11 15:50:03 +0900634 NetworkType networkType, boolean install) {
635 TrafficTreatment treatment;
daniel parkb5817102018-02-15 00:18:51 +0900636 OpenstackNode sourceNatGateway = osNodeService.completeNodes(GATEWAY).stream().findFirst().orElse(null);
637
638 if (sourceNatGateway == null) {
639 return;
640 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900641
daniel parkee8700b2017-05-11 15:50:03 +0900642 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
643 .matchEthType(Ethernet.TYPE_IPV4)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900644 .matchIPSrc(srcSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900645 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
646
647 switch (networkType) {
648 case VXLAN:
649 sBuilder.matchTunnelId(Long.parseLong(segmentId));
daniel parkee8700b2017-05-11 15:50:03 +0900650 break;
651 case VLAN:
652 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
daniel parkee8700b2017-05-11 15:50:03 +0900653 break;
654 default:
Jian Li71670d12018-03-02 21:31:07 +0900655 final String error = String.format("%s %s",
656 ERR_UNSUPPORTED_NET_TYPE,
daniel parkee8700b2017-05-11 15:50:03 +0900657 networkType.toString());
658 throw new IllegalStateException(error);
659 }
660
661 treatment = DefaultTrafficTreatment.builder()
daniel parkb5817102018-02-15 00:18:51 +0900662 .extension(buildExtension(
663 deviceService,
664 osNode.intgBridge(),
665 sourceNatGateway.dataIp().getIp4Address()),
666 osNode.intgBridge())
667 .setOutput(osNode.tunnelPortNum())
Hyunsun Moon44aac662017-02-18 02:07:01 +0900668 .build();
669
sanghodc375372017-06-08 10:41:30 +0900670 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900671 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900672 osNode.intgBridge(),
daniel parkee8700b2017-05-11 15:50:03 +0900673 sBuilder.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900674 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900675 PRIORITY_EXTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900676 ROUTING_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900677 install);
678 }
679
sangho072c4dd2017-05-17 10:45:21 +0900680 private void setRulesForSnatIngressRule(DeviceId deviceId, Long vni, IpPrefix destVmIp,
681 DeviceId dstDeviceId, boolean install) {
682
683 TrafficSelector selector = DefaultTrafficSelector.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900684 .matchEthType(Ethernet.TYPE_IPV4)
sangho072c4dd2017-05-17 10:45:21 +0900685 .matchIPDst(destVmIp)
686 .build();
Hyunsun Moon0d457362017-06-27 17:19:41 +0900687
sangho072c4dd2017-05-17 10:45:21 +0900688 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
689 .setTunnelId(vni)
690 .extension(buildExtension(
691 deviceService,
692 deviceId,
693 osNodeService.node(dstDeviceId).dataIp().getIp4Address()),
694 deviceId)
695 .setOutput(osNodeService.node(deviceId).tunnelPortNum())
696 .build();
daniel parkee8700b2017-05-11 15:50:03 +0900697
sanghodc375372017-06-08 10:41:30 +0900698 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900699 appId,
sangho072c4dd2017-05-17 10:45:21 +0900700 deviceId,
701 selector,
702 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900703 PRIORITY_EXTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900704 Constants.GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900705 install);
706 }
707
daniel parkb5817102018-02-15 00:18:51 +0900708 private void setRulesToGatewayWithDstIp(OpenstackNode osNode, OpenstackNode sourceNatGateway,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900709 String segmentId, IpAddress dstIp,
710 NetworkMode networkMode, boolean install) {
daniel parkee8700b2017-05-11 15:50:03 +0900711 TrafficSelector selector;
712 if (networkMode.equals(NetworkMode.VXLAN)) {
713 selector = DefaultTrafficSelector.builder()
714 .matchEthType(Ethernet.TYPE_IPV4)
715 .matchTunnelId(Long.valueOf(segmentId))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900716 .matchIPDst(dstIp.getIp4Address().toIpPrefix())
daniel parkee8700b2017-05-11 15:50:03 +0900717 .build();
718 } else {
719 selector = DefaultTrafficSelector.builder()
720 .matchEthType(Ethernet.TYPE_IPV4)
721 .matchVlanId(VlanId.vlanId(segmentId))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900722 .matchIPDst(dstIp.getIp4Address().toIpPrefix())
daniel parkee8700b2017-05-11 15:50:03 +0900723 .build();
724 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900725
726 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
daniel parkb5817102018-02-15 00:18:51 +0900727 .extension(buildExtension(
728 deviceService,
729 osNode.intgBridge(),
730 sourceNatGateway.dataIp().getIp4Address()),
731 osNode.intgBridge())
732 .setOutput(osNode.tunnelPortNum())
Hyunsun Moon44aac662017-02-18 02:07:01 +0900733 .build();
734
sanghodc375372017-06-08 10:41:30 +0900735 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900736 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900737 osNode.intgBridge(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900738 selector,
739 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900740 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900741 ROUTING_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900742 install);
743 }
744
sangho072c4dd2017-05-17 10:45:21 +0900745 private void setOvsNatIngressRule(DeviceId deviceId, IpPrefix cidr, MacAddress dstMac, boolean install) {
746
747 TrafficSelector selector = DefaultTrafficSelector.builder()
748 .matchEthType(Ethernet.TYPE_IPV4)
749 .matchIPDst(cidr)
750 .build();
751
752 ExtensionTreatment natTreatment = RulePopulatorUtil.niciraConnTrackTreatmentBuilder(driverService, deviceId)
753 .commit(false)
754 .natAction(true)
755 .table((short) 0)
756 .build();
757
758 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
759 .setEthDst(dstMac)
760 .extension(natTreatment, deviceId)
761 .build();
762
763 osFlowRuleService.setRule(
764 appId,
765 deviceId,
766 selector,
767 treatment,
sanghoe765ce22017-06-23 17:54:57 +0900768 PRIORITY_STATEFUL_SNAT_RULE,
sangho072c4dd2017-05-17 10:45:21 +0900769 GW_COMMON_TABLE,
770 install);
771 }
772
773 private void setOvsNatEgressRule(DeviceId deviceId, IpAddress natAddress, long vni, PortNumber output,
774 boolean install) {
775
776 TrafficSelector selector = DefaultTrafficSelector.builder()
777 .matchEthType(Ethernet.TYPE_IPV4)
778 .matchEthDst(DEFAULT_GATEWAY_MAC)
779 .matchTunnelId(vni)
780 .build();
781
782 ExtensionTreatment natTreatment = RulePopulatorUtil.niciraConnTrackTreatmentBuilder(driverService, deviceId)
783 .commit(true)
784 .natAction(true)
785 .natIp(natAddress)
786 .build();
787
788 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
789 .extension(natTreatment, deviceId)
790 .setEthDst(DEFAULT_EXTERNAL_ROUTER_MAC)
791 .setEthSrc(DEFAULT_GATEWAY_MAC)
792 .setOutput(output)
793 .build();
794
795 osFlowRuleService.setRule(
796 appId,
797 deviceId,
798 selector,
799 treatment,
sanghoe765ce22017-06-23 17:54:57 +0900800 PRIORITY_STATEFUL_SNAT_RULE,
sangho072c4dd2017-05-17 10:45:21 +0900801 GW_COMMON_TABLE,
802 install);
803 }
804
sanghoe765ce22017-06-23 17:54:57 +0900805 private void setRulesToController(DeviceId deviceId, String segmentId, IpPrefix srcSubnet,
806 NetworkType networkType, boolean install) {
807 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
808 .matchEthType(Ethernet.TYPE_IPV4)
809 .matchIPSrc(srcSubnet);
810
811 switch (networkType) {
812 case VXLAN:
813 sBuilder.matchTunnelId(Long.parseLong(segmentId))
814 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
815 break;
816 case VLAN:
817 sBuilder.matchVlanId(VlanId.vlanId(segmentId))
818 .matchEthDst(osNodeService.node(deviceId).vlanPortMac());
819 break;
820 default:
Jian Li71670d12018-03-02 21:31:07 +0900821 final String error = String.format("%s %s",
822 ERR_UNSUPPORTED_NET_TYPE,
sanghoe765ce22017-06-23 17:54:57 +0900823 networkType.toString());
824 throw new IllegalStateException(error);
825 }
826
827 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
828 .setEthDst(Constants.DEFAULT_GATEWAY_MAC);
829
830 if (networkType.equals(NetworkType.VLAN)) {
831 tBuilder.popVlan();
832 }
833
834 tBuilder.setOutput(PortNumber.CONTROLLER);
835
836 osFlowRuleService.setRule(
837 appId,
838 deviceId,
839 sBuilder.build(),
840 tBuilder.build(),
841 PRIORITY_EXTERNAL_ROUTING_RULE,
842 GW_COMMON_TABLE,
843 install);
844
845
846 // Sends ICMP response to controller for SNATing ingress traffic
847 TrafficSelector selector = DefaultTrafficSelector.builder()
848 .matchEthType(Ethernet.TYPE_IPV4)
849 .matchIPProtocol(IPv4.PROTOCOL_ICMP)
850 .matchIcmpType(ICMP.TYPE_ECHO_REPLY)
851 .build();
852
853 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
854 .setOutput(PortNumber.CONTROLLER)
855 .build();
856
857 osFlowRuleService.setRule(
858 appId,
859 deviceId,
860 selector,
861 treatment,
862 PRIORITY_INTERNAL_ROUTING_RULE,
863 GW_COMMON_TABLE,
864 install);
865 }
sangho072c4dd2017-05-17 10:45:21 +0900866
Frank Wang245a6822017-06-14 09:51:35 +0800867 private void setRouterAdminRules(String segmentId, NetworkType networkType, boolean install) {
868 TrafficTreatment treatment;
869 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
870 .matchEthType(Ethernet.TYPE_IPV4);
871
872 switch (networkType) {
873 case VXLAN:
874 sBuilder.matchTunnelId(Long.parseLong(segmentId));
875 break;
876 case VLAN:
877 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
878 break;
879 default:
Jian Li71670d12018-03-02 21:31:07 +0900880 final String error = String.format("%s %s",
881 ERR_UNSUPPORTED_NET_TYPE,
Frank Wang245a6822017-06-14 09:51:35 +0800882 networkType.toString());
883 throw new IllegalStateException(error);
884 }
885
886 treatment = DefaultTrafficTreatment.builder()
887 .drop()
888 .build();
889
890 osNodeService.completeNodes().stream()
891 .filter(osNode -> osNode.type() == COMPUTE)
892 .forEach(osNode -> {
893 osFlowRuleService.setRule(
894 appId,
895 osNode.intgBridge(),
896 sBuilder.build(),
897 treatment,
898 PRIORITY_ADMIN_RULE,
899 ROUTING_TABLE,
900 install);
901 });
902 }
903
Hyunsun Moon44aac662017-02-18 02:07:01 +0900904 private class InternalRouterEventListener implements OpenstackRouterListener {
905
906 @Override
907 public boolean isRelevant(OpenstackRouterEvent event) {
908 // do not allow to proceed without leadership
909 NodeId leader = leadershipService.getLeader(appId.name());
910 return Objects.equals(localNodeId, leader);
911 }
912
913 // FIXME only one leader in the cluster should process
914 @Override
915 public void event(OpenstackRouterEvent event) {
916 switch (event.type()) {
917 case OPENSTACK_ROUTER_CREATED:
918 log.debug("Router(name:{}, ID:{}) is created",
919 event.subject().getName(),
920 event.subject().getId());
921 eventExecutor.execute(() -> routerUpdated(event.subject()));
922 break;
923 case OPENSTACK_ROUTER_UPDATED:
924 log.debug("Router(name:{}, ID:{}) is updated",
925 event.subject().getName(),
926 event.subject().getId());
927 eventExecutor.execute(() -> routerUpdated(event.subject()));
928 break;
929 case OPENSTACK_ROUTER_REMOVED:
930 log.debug("Router(name:{}, ID:{}) is removed",
931 event.subject().getName(),
932 event.subject().getId());
Frank Wang245a6822017-06-14 09:51:35 +0800933 eventExecutor.execute(() -> routerRemove(event.subject()));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900934 break;
935 case OPENSTACK_ROUTER_INTERFACE_ADDED:
936 log.debug("Router interface {} added to router {}",
937 event.routerIface().getPortId(),
938 event.routerIface().getId());
939 eventExecutor.execute(() -> routerIfaceAdded(
940 event.subject(),
941 event.routerIface()));
942 break;
943 case OPENSTACK_ROUTER_INTERFACE_UPDATED:
944 log.debug("Router interface {} on {} updated",
945 event.routerIface().getPortId(),
946 event.routerIface().getId());
947 break;
948 case OPENSTACK_ROUTER_INTERFACE_REMOVED:
949 log.debug("Router interface {} removed from router {}",
950 event.routerIface().getPortId(),
951 event.routerIface().getId());
952 eventExecutor.execute(() -> routerIfaceRemoved(
953 event.subject(),
954 event.routerIface()));
955 break;
956 case OPENSTACK_ROUTER_GATEWAY_ADDED:
daniel parkb5817102018-02-15 00:18:51 +0900957 log.debug("Router external gateway {} added", event.externalGateway().getNetworkId());
Ray Milkey08932a72018-02-20 15:34:38 -0800958 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900959 case OPENSTACK_ROUTER_GATEWAY_REMOVED:
daniel parkb5817102018-02-15 00:18:51 +0900960 log.debug("Router external gateway {} removed", event.externalGateway().getNetworkId());
Ray Milkey08932a72018-02-20 15:34:38 -0800961 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900962 case OPENSTACK_FLOATING_IP_CREATED:
963 case OPENSTACK_FLOATING_IP_UPDATED:
964 case OPENSTACK_FLOATING_IP_REMOVED:
965 case OPENSTACK_FLOATING_IP_ASSOCIATED:
966 case OPENSTACK_FLOATING_IP_DISASSOCIATED:
967 default:
968 // do nothing for the other events
969 break;
970 }
971 }
972 }
973
974 private class InternalNodeEventListener implements OpenstackNodeListener {
975
976 @Override
977 public boolean isRelevant(OpenstackNodeEvent event) {
978 // do not allow to proceed without leadership
979 NodeId leader = leadershipService.getLeader(appId.name());
980 return Objects.equals(localNodeId, leader);
981 }
982
983 @Override
984 public void event(OpenstackNodeEvent event) {
985 OpenstackNode osNode = event.subject();
986
987 switch (event.type()) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900988 case OPENSTACK_NODE_COMPLETE:
989 case OPENSTACK_NODE_INCOMPLETE:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900990 eventExecutor.execute(() -> {
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900991 log.info("Reconfigure routers for {}", osNode.hostname());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900992 reconfigureRouters();
993 });
994 break;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900995 case OPENSTACK_NODE_CREATED:
996 case OPENSTACK_NODE_UPDATED:
997 case OPENSTACK_NODE_REMOVED:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900998 default:
999 break;
1000 }
1001 }
1002
1003 private void reconfigureRouters() {
1004 osRouterService.routers().forEach(osRouter -> {
1005 routerUpdated(osRouter);
1006 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
1007 routerIfaceAdded(osRouter, iface);
1008 });
1009 });
1010 }
1011 }
sangho072c4dd2017-05-17 10:45:21 +09001012
1013 private class InternalInstancePortListener implements InstancePortListener {
1014
1015 @Override
1016 public boolean isRelevant(InstancePortEvent event) {
1017 InstancePort instPort = event.subject();
1018 return mastershipService.isLocalMaster(instPort.deviceId());
1019 }
1020
1021 @Override
1022 public void event(InstancePortEvent event) {
1023 InstancePort instPort = event.subject();
1024 switch (event.type()) {
1025 case OPENSTACK_INSTANCE_PORT_UPDATED:
1026 case OPENSTACK_INSTANCE_PORT_DETECTED:
1027 eventExecutor.execute(() -> {
1028 log.info("RoutingHandler: Instance port detected MAC:{} IP:{}",
1029 instPort.macAddress(),
1030 instPort.ipAddress());
1031 instPortDetected(event.subject());
1032 });
1033 break;
1034 case OPENSTACK_INSTANCE_PORT_VANISHED:
1035 eventExecutor.execute(() -> {
1036 log.info("RoutingHandler: Instance port vanished MAC:{} IP:{}",
1037 instPort.macAddress(),
1038 instPort.ipAddress());
1039 instPortRemoved(event.subject());
1040 });
1041 break;
1042 default:
1043 break;
1044 }
1045 }
1046
1047 private void instPortDetected(InstancePort instPort) {
daniel park796c2eb2018-03-22 17:01:51 +09001048 if (osNetworkAdminService.network(instPort.networkId()).getNetworkType() == NetworkType.FLAT) {
1049 return;
1050 }
sangho072c4dd2017-05-17 10:45:21 +09001051 osNodeService.completeNodes(GATEWAY)
1052 .forEach(gwNode -> setRulesForSnatIngressRule(gwNode.intgBridge(),
1053 Long.parseLong(osNetworkService.network(instPort.networkId()).getProviderSegID()),
1054 IpPrefix.valueOf(instPort.ipAddress(), 32),
1055 instPort.deviceId(),
1056 true));
1057 }
1058
1059 private void instPortRemoved(InstancePort instPort) {
daniel park796c2eb2018-03-22 17:01:51 +09001060 if (osNetworkAdminService.network(instPort.networkId()).getNetworkType() == NetworkType.FLAT) {
1061 return;
1062 }
sangho072c4dd2017-05-17 10:45:21 +09001063 osNodeService.completeNodes(GATEWAY)
1064 .forEach(gwNode -> setRulesForSnatIngressRule(gwNode.intgBridge(),
1065 Long.parseLong(osNetworkService.network(instPort.networkId()).getProviderSegID()),
1066 IpPrefix.valueOf(instPort.ipAddress(), 32),
1067 instPort.deviceId(),
1068 false));
1069 }
1070 }
Hyunsun Moon44aac662017-02-18 02:07:01 +09001071}