blob: 4cc241f757b7e1e1f700e0ac7a570875b9b11874 [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;
Hyunsun Moon44aac662017-02-18 02:07:01 +090020import org.onlab.packet.Ethernet;
Jian Lifdb8d872019-04-08 10:38:58 +090021import org.onlab.packet.ICMP;
Hyunsun Moon44aac662017-02-18 02:07:01 +090022import org.onlab.packet.IPv4;
23import org.onlab.packet.IpAddress;
24import org.onlab.packet.IpPrefix;
daniel parkee8700b2017-05-11 15:50:03 +090025import org.onlab.packet.VlanId;
Jian Li25257212019-03-26 13:31:14 +090026import org.onosproject.cfg.ComponentConfigService;
27import org.onosproject.cfg.ConfigProperty;
Hyunsun Moon44aac662017-02-18 02:07:01 +090028import org.onosproject.cluster.ClusterService;
29import org.onosproject.cluster.LeadershipService;
30import org.onosproject.cluster.NodeId;
31import org.onosproject.core.ApplicationId;
32import org.onosproject.core.CoreService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090033import org.onosproject.net.DeviceId;
34import org.onosproject.net.PortNumber;
sangho072c4dd2017-05-17 10:45:21 +090035import org.onosproject.net.device.DeviceService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090036import org.onosproject.net.flow.DefaultTrafficSelector;
37import org.onosproject.net.flow.DefaultTrafficTreatment;
38import org.onosproject.net.flow.TrafficSelector;
39import org.onosproject.net.flow.TrafficTreatment;
Hyunsun Moon44aac662017-02-18 02:07:01 +090040import org.onosproject.openstacknetworking.api.Constants;
sangho072c4dd2017-05-17 10:45:21 +090041import org.onosproject.openstacknetworking.api.InstancePortService;
sanghodc375372017-06-08 10:41:30 +090042import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
SONA Project6bc5c4a2018-12-14 23:49:52 +090043import org.onosproject.openstacknetworking.api.OpenstackNetwork.Type;
daniel park32b42202018-03-14 16:53:44 +090044import org.onosproject.openstacknetworking.api.OpenstackNetworkAdminService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090045import org.onosproject.openstacknetworking.api.OpenstackRouterEvent;
46import org.onosproject.openstacknetworking.api.OpenstackRouterListener;
47import org.onosproject.openstacknetworking.api.OpenstackRouterService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090048import org.onosproject.openstacknode.api.OpenstackNode;
Hyunsun Moon0d457362017-06-27 17:19:41 +090049import org.onosproject.openstacknode.api.OpenstackNodeEvent;
50import org.onosproject.openstacknode.api.OpenstackNodeListener;
51import org.onosproject.openstacknode.api.OpenstackNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090052import org.openstack4j.model.network.Network;
53import org.openstack4j.model.network.Router;
54import org.openstack4j.model.network.RouterInterface;
55import org.openstack4j.model.network.Subnet;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070056import org.osgi.service.component.annotations.Activate;
57import org.osgi.service.component.annotations.Component;
58import org.osgi.service.component.annotations.Deactivate;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070059import org.osgi.service.component.annotations.Reference;
60import org.osgi.service.component.annotations.ReferenceCardinality;
Hyunsun Moon44aac662017-02-18 02:07:01 +090061import org.slf4j.Logger;
62import org.slf4j.LoggerFactory;
63
64import java.util.Objects;
65import java.util.Set;
66import java.util.concurrent.ExecutorService;
67import java.util.stream.Collectors;
68
69import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
70import static org.onlab.util.Tools.groupedThreads;
Jian Li25257212019-03-26 13:31:14 +090071import static org.onosproject.openstacknetworking.api.Constants.ARP_BROADCAST_MODE;
sangho072c4dd2017-05-17 10:45:21 +090072import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
daniel park796c2eb2018-03-22 17:01:51 +090073import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ADMIN_RULE;
Jian Lifdb8d872019-04-08 10:38:58 +090074import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ICMP_REQUEST_RULE;
sangho072c4dd2017-05-17 10:45:21 +090075import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ICMP_RULE;
76import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_INTERNAL_ROUTING_RULE;
sangho072c4dd2017-05-17 10:45:21 +090077import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_SWITCHING_RULE;
78import static org.onosproject.openstacknetworking.api.Constants.ROUTING_TABLE;
Jian Li8abf2fe2018-06-12 18:42:30 +090079import static org.onosproject.openstacknetworking.api.Constants.STAT_OUTBOUND_TABLE;
Jian Li25257212019-03-26 13:31:14 +090080import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.ARP_MODE;
81import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.USE_STATEFUL_SNAT;
82import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValue;
83import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValueAsBoolean;
Jian Li2d68c192018-12-13 15:52:59 +090084import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.tunnelPortNumByNetType;
Jian Li26949762018-03-30 15:46:37 +090085import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
Hyunsun Moon0d457362017-06-27 17:19:41 +090086import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
87import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Hyunsun Moon44aac662017-02-18 02:07:01 +090088
89/**
90 * Handles OpenStack router events.
91 */
Jian Li33b4db52019-03-20 18:22:38 +090092@Component(immediate = true)
Hyunsun Moon44aac662017-02-18 02:07:01 +090093public class OpenstackRoutingHandler {
94
95 private final Logger log = LoggerFactory.getLogger(getClass());
96
97 private static final String MSG_ENABLED = "Enabled ";
98 private static final String MSG_DISABLED = "Disabled ";
daniel parkee8700b2017-05-11 15:50:03 +090099 private static final String ERR_UNSUPPORTED_NET_TYPE = "Unsupported network type";
sanghoe765ce22017-06-23 17:54:57 +0900100
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700101 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900102 protected CoreService coreService;
103
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700104 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900105 protected LeadershipService leadershipService;
106
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700107 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900108 protected ClusterService clusterService;
109
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700110 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li25257212019-03-26 13:31:14 +0900111 protected ComponentConfigService configService;
112
113 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900114 protected OpenstackNodeService osNodeService;
115
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700116 @Reference(cardinality = ReferenceCardinality.MANDATORY)
daniel park32b42202018-03-14 16:53:44 +0900117 protected OpenstackNetworkAdminService osNetworkAdminService;
118
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700119 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900120 protected OpenstackRouterService osRouterService;
121
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700122 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho072c4dd2017-05-17 10:45:21 +0900123 protected InstancePortService instancePortService;
124
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700125 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho072c4dd2017-05-17 10:45:21 +0900126 protected DeviceService deviceService;
127
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700128 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sanghodc375372017-06-08 10:41:30 +0900129 protected OpenstackFlowRuleService osFlowRuleService;
130
Hyunsun Moon44aac662017-02-18 02:07:01 +0900131 private final ExecutorService eventExecutor = newSingleThreadScheduledExecutor(
132 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
133 private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
134 private final OpenstackRouterListener osRouterListener = new InternalRouterEventListener();
135
136 private ApplicationId appId;
137 private NodeId localNodeId;
138
139 @Activate
140 protected void activate() {
141 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
142 localNodeId = clusterService.getLocalNode().id();
143 leadershipService.runForLeadership(appId.name());
144 osNodeService.addListener(osNodeListener);
145 osRouterService.addListener(osRouterListener);
146
147 log.info("Started");
148 }
149
150 @Deactivate
151 protected void deactivate() {
152 osRouterService.removeListener(osRouterListener);
153 osNodeService.removeListener(osNodeListener);
154 leadershipService.withdraw(appId.name());
155 eventExecutor.shutdown();
156
157 log.info("Stopped");
158 }
159
160 private void routerUpdated(Router osRouter) {
Frank Wang245a6822017-06-14 09:51:35 +0800161 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
Jian Li5ecfd1a2018-12-10 11:41:03 +0900162 Network network = osNetworkAdminService.network(
163 osNetworkAdminService.subnet(iface.getSubnetId())
Frank Wang245a6822017-06-14 09:51:35 +0800164 .getNetworkId());
SONA Project6bc5c4a2018-12-14 23:49:52 +0900165 Type netType = osNetworkAdminService.networkType(
166 osNetworkAdminService.subnet(iface.getSubnetId())
167 .getNetworkId());
Jian Li5ecfd1a2018-12-10 11:41:03 +0900168 setRouterAdminRules(network.getProviderSegID(),
SONA Project6bc5c4a2018-12-14 23:49:52 +0900169 netType, !osRouter.isAdminStateUp());
Frank Wang245a6822017-06-14 09:51:35 +0800170 });
Daniel Park613ac372018-06-28 14:30:11 +0900171 }
172
Frank Wang245a6822017-06-14 09:51:35 +0800173 private void routerRemove(Router osRouter) {
174 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
Jian Li5ecfd1a2018-12-10 11:41:03 +0900175 Network network = osNetworkAdminService.network(
176 osNetworkAdminService.subnet(iface.getSubnetId())
Frank Wang245a6822017-06-14 09:51:35 +0800177 .getNetworkId());
SONA Project6bc5c4a2018-12-14 23:49:52 +0900178 Type netType = osNetworkAdminService.networkType(
179 osNetworkAdminService.subnet(iface.getSubnetId())
180 .getNetworkId());
181 setRouterAdminRules(network.getProviderSegID(), netType, false);
Frank Wang245a6822017-06-14 09:51:35 +0800182 });
183 }
184
Hyunsun Moon44aac662017-02-18 02:07:01 +0900185 private void routerIfaceAdded(Router osRouter, RouterInterface osRouterIface) {
Jian Liedc8b762018-03-22 15:42:00 +0900186 Subnet osSubnet = osNetworkAdminService.subnet(osRouterIface.getSubnetId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900187 if (osSubnet == null) {
188 final String error = String.format(
Jian Li71670d12018-03-02 21:31:07 +0900189 "Failed to set flows for router %s: subnet %s does not exist",
Hyunsun Moon44aac662017-02-18 02:07:01 +0900190 osRouterIface.getId(),
191 osRouterIface.getSubnetId());
192 throw new IllegalStateException(error);
193 }
Frank Wang245a6822017-06-14 09:51:35 +0800194
195 if (!osRouter.isAdminStateUp()) {
Jian Liedc8b762018-03-22 15:42:00 +0900196 Network network = osNetworkAdminService.network(osSubnet.getNetworkId());
SONA Project6bc5c4a2018-12-14 23:49:52 +0900197 Type netType = osNetworkAdminService.networkType(osSubnet.getNetworkId());
198 setRouterAdminRules(network.getProviderSegID(), netType, true);
Frank Wang245a6822017-06-14 09:51:35 +0800199 }
200
Hyunsun Moon44aac662017-02-18 02:07:01 +0900201 setInternalRoutes(osRouter, osSubnet, true);
Jian Li25257212019-03-26 13:31:14 +0900202 setGatewayRules(osSubnet, osRouter, true);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900203 log.info("Connected subnet({}) to {}", osSubnet.getCidr(), osRouter.getName());
204 }
205
206 private void routerIfaceRemoved(Router osRouter, RouterInterface osRouterIface) {
Jian Liedc8b762018-03-22 15:42:00 +0900207 Subnet osSubnet = osNetworkAdminService.subnet(osRouterIface.getSubnetId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900208 if (osSubnet == null) {
209 final String error = String.format(
Jian Li71670d12018-03-02 21:31:07 +0900210 "Failed to set flows for router %s: subnet %s does not exist",
Hyunsun Moon44aac662017-02-18 02:07:01 +0900211 osRouterIface.getId(),
212 osRouterIface.getSubnetId());
213 throw new IllegalStateException(error);
214 }
215
Frank Wang245a6822017-06-14 09:51:35 +0800216 if (!osRouter.isAdminStateUp()) {
Jian Liedc8b762018-03-22 15:42:00 +0900217 Network network = osNetworkAdminService.network(osSubnet.getNetworkId());
SONA Project6bc5c4a2018-12-14 23:49:52 +0900218 Type netType = osNetworkAdminService.networkType(osSubnet.getNetworkId());
219 setRouterAdminRules(network.getProviderSegID(), netType, false);
Frank Wang245a6822017-06-14 09:51:35 +0800220 }
221
Hyunsun Moon44aac662017-02-18 02:07:01 +0900222 setInternalRoutes(osRouter, osSubnet, false);
Jian Li25257212019-03-26 13:31:14 +0900223 setGatewayRules(osSubnet, osRouter, false);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900224 log.info("Disconnected subnet({}) from {}", osSubnet.getCidr(), osRouter.getName());
225 }
226
Jian Li25257212019-03-26 13:31:14 +0900227 private void setGatewayRules(Subnet osSubnet, Router osRouter, boolean install) {
Jian Li4d138702018-11-27 17:25:28 +0900228 OpenstackNode srcNatGw = osNodeService.completeNodes(GATEWAY)
229 .stream().findFirst().orElse(null);
daniel parkb5817102018-02-15 00:18:51 +0900230
Jian Li4d138702018-11-27 17:25:28 +0900231 if (srcNatGw == null) {
daniel parkb5817102018-02-15 00:18:51 +0900232 return;
233 }
234
Hyunsun Moon44aac662017-02-18 02:07:01 +0900235 if (Strings.isNullOrEmpty(osSubnet.getGateway())) {
236 // do nothing if no gateway is set
237 return;
238 }
239
Jian Li4d138702018-11-27 17:25:28 +0900240 Network net = osNetworkAdminService.network(osSubnet.getNetworkId());
Jian Li621f73c2018-12-15 01:49:22 +0900241 Type netType = osNetworkAdminService.networkType(osSubnet.getNetworkId());
Daniel Park51f9d1e2018-10-26 13:39:09 +0900242 Set<Subnet> routableSubnets = routableSubnets(osRouter, osSubnet.getId());
243
Jian Li25257212019-03-26 13:31:14 +0900244 // install rules to each compute node for routing IP packets to gateways
245 osNodeService.completeNodes(COMPUTE).stream()
246 .filter(cNode -> cNode.dataIp() != null)
247 .forEach(cNode -> setRulesToGatewayWithRoutableSubnets(
248 cNode,
249 srcNatGw,
250 net.getProviderSegID(),
251 osSubnet,
252 routableSubnets,
253 netType,
254 install));
255
Jian Lifdb8d872019-04-08 10:38:58 +0900256 // install rules to punt ICMP packets to controller at gateway node
257 // this rule is only valid for stateless ICMP SNAT case
258 osNodeService.completeNodes(GATEWAY).forEach(gNode ->
259 setReactiveGatewayIcmpRule(
260 IpAddress.valueOf(osSubnet.getGateway()),
261 gNode.intgBridge(), install));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900262
Hyunsun Moon44aac662017-02-18 02:07:01 +0900263 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
Jian Li25257212019-03-26 13:31:14 +0900264 log.debug(updateStr + "IP to {}", osSubnet.getGateway());
Jian Li4d138702018-11-27 17:25:28 +0900265 }
266
Hyunsun Moon44aac662017-02-18 02:07:01 +0900267 private void setInternalRoutes(Router osRouter, Subnet updatedSubnet, boolean install) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900268 Type netType = osNetworkAdminService.networkType(updatedSubnet.getNetworkId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900269 Set<Subnet> routableSubnets = routableSubnets(osRouter, updatedSubnet.getId());
Jian Lib6969502018-10-30 20:38:07 +0900270 String updatedSegmentId = getSegmentId(updatedSubnet);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900271
272 // installs rule from/to my subnet intentionally to fix ICMP failure
273 // to my subnet gateway if no external gateway added to the router
Hyunsun Moon0d457362017-06-27 17:19:41 +0900274 osNodeService.completeNodes(COMPUTE).forEach(cNode -> {
275 setInternalRouterRules(
276 cNode.intgBridge(),
Jian Lib6969502018-10-30 20:38:07 +0900277 updatedSegmentId,
278 updatedSegmentId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900279 IpPrefix.valueOf(updatedSubnet.getCidr()),
280 IpPrefix.valueOf(updatedSubnet.getCidr()),
SONA Project6bc5c4a2018-12-14 23:49:52 +0900281 netType,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900282 install
283 );
Hyunsun Moon44aac662017-02-18 02:07:01 +0900284
Hyunsun Moon0d457362017-06-27 17:19:41 +0900285 routableSubnets.forEach(subnet -> {
286 setInternalRouterRules(
287 cNode.intgBridge(),
Jian Lib6969502018-10-30 20:38:07 +0900288 updatedSegmentId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900289 getSegmentId(subnet),
290 IpPrefix.valueOf(updatedSubnet.getCidr()),
291 IpPrefix.valueOf(subnet.getCidr()),
SONA Project6bc5c4a2018-12-14 23:49:52 +0900292 netType,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900293 install
294 );
295 setInternalRouterRules(
296 cNode.intgBridge(),
297 getSegmentId(subnet),
Jian Lib6969502018-10-30 20:38:07 +0900298 updatedSegmentId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900299 IpPrefix.valueOf(subnet.getCidr()),
300 IpPrefix.valueOf(updatedSubnet.getCidr()),
SONA Project6bc5c4a2018-12-14 23:49:52 +0900301 netType,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900302 install
303 );
304 });
305 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900306
daniel parkee8700b2017-05-11 15:50:03 +0900307
Hyunsun Moon44aac662017-02-18 02:07:01 +0900308 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
309 routableSubnets.forEach(subnet -> log.debug(
310 updateStr + "route between subnet:{} and subnet:{}",
311 subnet.getCidr(),
312 updatedSubnet.getCidr()));
313 }
314
315 private Set<Subnet> routableSubnets(Router osRouter, String osSubnetId) {
316 Set<Subnet> osSubnets = osRouterService.routerInterfaces(osRouter.getId())
317 .stream()
318 .filter(iface -> !Objects.equals(iface.getSubnetId(), osSubnetId))
Jian Liedc8b762018-03-22 15:42:00 +0900319 .map(iface -> osNetworkAdminService.subnet(iface.getSubnetId()))
Hyunsun Moon44aac662017-02-18 02:07:01 +0900320 .collect(Collectors.toSet());
321 return ImmutableSet.copyOf(osSubnets);
322 }
323
daniel parkee8700b2017-05-11 15:50:03 +0900324 private String getSegmentId(Subnet osSubnet) {
Jian Liedc8b762018-03-22 15:42:00 +0900325 return osNetworkAdminService.network(osSubnet.getNetworkId()).getProviderSegID();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900326 }
327
Jian Li25257212019-03-26 13:31:14 +0900328 private boolean getStatefulSnatFlag() {
329 Set<ConfigProperty> properties = configService.getProperties(OpenstackRoutingSnatHandler.class.getName());
330 return getPropertyValueAsBoolean(properties, USE_STATEFUL_SNAT);
331 }
332
333 private String getArpMode() {
334 Set<ConfigProperty> properties = configService.getProperties(OpenstackRoutingArpHandler.class.getName());
335 return getPropertyValue(properties, ARP_MODE);
336 }
337
338 private void setReactiveGatewayIcmpRule(IpAddress gatewayIp, DeviceId deviceId, boolean install) {
Jian Lifdb8d872019-04-08 10:38:58 +0900339
340 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
341 int icmpRulePriority;
342
343 if (getStatefulSnatFlag()) {
344 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
345 .matchIPProtocol(IPv4.PROTOCOL_ICMP)
346 .matchIcmpType(ICMP.TYPE_ECHO_REQUEST);
347 icmpRulePriority = PRIORITY_ICMP_REQUEST_RULE;
348 } else {
349 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
350 .matchIPProtocol(IPv4.PROTOCOL_ICMP)
351 .matchIPDst(gatewayIp.getIp4Address().toIpPrefix());
352 icmpRulePriority = PRIORITY_ICMP_RULE;
353 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900354
355 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Li4d5c5c32018-04-02 16:38:18 +0900356 .punt()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900357 .build();
358
sanghodc375372017-06-08 10:41:30 +0900359 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900360 appId,
361 deviceId,
Jian Lifdb8d872019-04-08 10:38:58 +0900362 sBuilder.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900363 treatment,
Jian Lifdb8d872019-04-08 10:38:58 +0900364 icmpRulePriority,
sanghodc375372017-06-08 10:41:30 +0900365 Constants.GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900366 install);
367 }
368
Jian Li4d138702018-11-27 17:25:28 +0900369 private void setInternalRouterRules(DeviceId deviceId, String srcSegId, String dstSegId,
daniel parkee8700b2017-05-11 15:50:03 +0900370 IpPrefix srcSubnet, IpPrefix dstSubnet,
SONA Project6bc5c4a2018-12-14 23:49:52 +0900371 Type networkType, boolean install) {
Jian Li4d138702018-11-27 17:25:28 +0900372
daniel parkee8700b2017-05-11 15:50:03 +0900373 switch (networkType) {
374 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900375 case GRE:
Jian Li621f73c2018-12-15 01:49:22 +0900376 case GENEVE:
Jian Li2d68c192018-12-13 15:52:59 +0900377 setInternalRouterRulesForTunnel(deviceId, srcSegId, dstSegId,
Jian Li4d138702018-11-27 17:25:28 +0900378 srcSubnet, dstSubnet, install);
daniel parkee8700b2017-05-11 15:50:03 +0900379 break;
380 case VLAN:
Jian Li4d138702018-11-27 17:25:28 +0900381 setInternalRouterRulesForVlan(deviceId, srcSegId, dstSegId,
382 srcSubnet, dstSubnet, install);
daniel parkee8700b2017-05-11 15:50:03 +0900383 break;
384 default:
Jian Li4d138702018-11-27 17:25:28 +0900385 final String error = String.format("%s %s", ERR_UNSUPPORTED_NET_TYPE,
386 networkType.toString());
daniel parkee8700b2017-05-11 15:50:03 +0900387 throw new IllegalStateException(error);
388 }
389
Hyunsun Moon44aac662017-02-18 02:07:01 +0900390 }
391
Jian Li2d68c192018-12-13 15:52:59 +0900392 private void setInternalRouterRulesForTunnel(DeviceId deviceId,
393 String srcSegmentId,
394 String dstSegmentId,
395 IpPrefix srcSubnet,
396 IpPrefix dstSubnet,
397 boolean install) {
Jian Li4d138702018-11-27 17:25:28 +0900398 TrafficSelector selector;
399 TrafficTreatment treatment;
400 selector = DefaultTrafficSelector.builder()
401 .matchEthType(Ethernet.TYPE_IPV4)
402 .matchTunnelId(Long.parseLong(srcSegmentId))
403 .matchIPSrc(srcSubnet.getIp4Prefix())
404 .matchIPDst(dstSubnet.getIp4Prefix())
405 .build();
406
407 treatment = DefaultTrafficTreatment.builder()
408 .setTunnelId(Long.parseLong(dstSegmentId))
409 .transition(STAT_OUTBOUND_TABLE)
410 .build();
411
412 osFlowRuleService.setRule(
413 appId,
414 deviceId,
415 selector,
416 treatment,
417 PRIORITY_INTERNAL_ROUTING_RULE,
418 ROUTING_TABLE,
419 install);
420
421 selector = DefaultTrafficSelector.builder()
422 .matchEthType(Ethernet.TYPE_IPV4)
423 .matchTunnelId(Long.parseLong(dstSegmentId))
424 .matchIPSrc(srcSubnet.getIp4Prefix())
425 .matchIPDst(dstSubnet.getIp4Prefix())
426 .build();
427
428 treatment = DefaultTrafficTreatment.builder()
429 .setTunnelId(Long.parseLong(dstSegmentId))
430 .transition(STAT_OUTBOUND_TABLE)
431 .build();
432
433 osFlowRuleService.setRule(
434 appId,
435 deviceId,
436 selector,
437 treatment,
438 PRIORITY_INTERNAL_ROUTING_RULE,
439 ROUTING_TABLE,
440 install);
441 }
442
443 private void setInternalRouterRulesForVlan(DeviceId deviceId,
444 String srcSegmentId,
445 String dstSegmentId,
446 IpPrefix srcSubnet,
447 IpPrefix dstSubnet,
448 boolean install) {
449 TrafficSelector selector;
450 TrafficTreatment treatment;
451 selector = DefaultTrafficSelector.builder()
452 .matchEthType(Ethernet.TYPE_IPV4)
453 .matchVlanId(VlanId.vlanId(srcSegmentId))
454 .matchIPSrc(srcSubnet.getIp4Prefix())
455 .matchIPDst(dstSubnet.getIp4Prefix())
456 .build();
457
458 treatment = DefaultTrafficTreatment.builder()
459 .setVlanId(VlanId.vlanId(dstSegmentId))
460 .transition(STAT_OUTBOUND_TABLE)
461 .build();
462
463 osFlowRuleService.setRule(
464 appId,
465 deviceId,
466 selector,
467 treatment,
468 PRIORITY_INTERNAL_ROUTING_RULE,
469 ROUTING_TABLE,
470 install);
471
472 selector = DefaultTrafficSelector.builder()
473 .matchEthType(Ethernet.TYPE_IPV4)
474 .matchVlanId(VlanId.vlanId(dstSegmentId))
475 .matchIPSrc(srcSubnet.getIp4Prefix())
476 .matchIPDst(dstSubnet.getIp4Prefix())
477 .build();
478
479 treatment = DefaultTrafficTreatment.builder()
480 .setVlanId(VlanId.vlanId(dstSegmentId))
481 .transition(STAT_OUTBOUND_TABLE)
482 .build();
483
484 osFlowRuleService.setRule(
485 appId,
486 deviceId,
487 selector,
488 treatment,
489 PRIORITY_INTERNAL_ROUTING_RULE,
490 ROUTING_TABLE,
491 install);
492 }
493
Jian Li5ecfd1a2018-12-10 11:41:03 +0900494 private void setRulesToGatewayWithRoutableSubnets(OpenstackNode osNode,
495 OpenstackNode sourceNatGateway,
496 String segmentId,
497 Subnet updatedSubnet,
498 Set<Subnet> routableSubnets,
SONA Project6bc5c4a2018-12-14 23:49:52 +0900499 Type networkType,
Daniel Park51f9d1e2018-10-26 13:39:09 +0900500 boolean install) {
Jian Li25257212019-03-26 13:31:14 +0900501
502 if (getStatefulSnatFlag() && ARP_BROADCAST_MODE.equals(getArpMode())) {
503 return;
504 }
505
506 // at first we install flow rules to gateway with segId and gatewayIp of updated subnet
Jian Li5ecfd1a2018-12-10 11:41:03 +0900507 setRulesToGatewayWithDstIp(osNode, sourceNatGateway, segmentId,
Jian Li2d68c192018-12-13 15:52:59 +0900508 IpAddress.valueOf(updatedSubnet.getGateway()), networkType, install);
Daniel Park51f9d1e2018-10-26 13:39:09 +0900509
510 routableSubnets.forEach(subnet -> {
511 setRulesToGatewayWithDstIp(osNode, sourceNatGateway,
512 segmentId, IpAddress.valueOf(subnet.getGateway()),
Jian Li2d68c192018-12-13 15:52:59 +0900513 networkType, install);
Daniel Park51f9d1e2018-10-26 13:39:09 +0900514
515 Network network = osNetworkAdminService.network(subnet.getNetworkId());
516 setRulesToGatewayWithDstIp(osNode, sourceNatGateway,
517 network.getProviderSegID(), IpAddress.valueOf(updatedSubnet.getGateway()),
Jian Li2d68c192018-12-13 15:52:59 +0900518 networkType, install);
Daniel Park51f9d1e2018-10-26 13:39:09 +0900519 });
520 }
521
Jian Li5ecfd1a2018-12-10 11:41:03 +0900522 private void setRulesToGatewayWithDstIp(OpenstackNode osNode,
523 OpenstackNode sourceNatGateway,
524 String segmentId,
525 IpAddress dstIp,
SONA Project6bc5c4a2018-12-14 23:49:52 +0900526 Type networkType,
Jian Li5ecfd1a2018-12-10 11:41:03 +0900527 boolean install) {
Daniel Parkc64b4c62018-05-09 18:13:39 +0900528 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
529 .matchEthType(Ethernet.TYPE_IPV4)
530 .matchIPDst(dstIp.getIp4Address().toIpPrefix());
531
Daniel Parkc64b4c62018-05-09 18:13:39 +0900532 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
533
Jian Li2d68c192018-12-13 15:52:59 +0900534 switch (networkType) {
Daniel Parkc64b4c62018-05-09 18:13:39 +0900535 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900536 case GRE:
Jian Li621f73c2018-12-15 01:49:22 +0900537 case GENEVE:
Daniel Park51f9d1e2018-10-26 13:39:09 +0900538 sBuilder.matchTunnelId(Long.parseLong(segmentId));
Jian Li2d68c192018-12-13 15:52:59 +0900539
SONA Project6bc5c4a2018-12-14 23:49:52 +0900540 PortNumber portNum = tunnelPortNumByNetType(networkType, osNode);
Jian Li2d68c192018-12-13 15:52:59 +0900541
Daniel Parkc64b4c62018-05-09 18:13:39 +0900542 tBuilder.extension(buildExtension(
daniel parkb5817102018-02-15 00:18:51 +0900543 deviceService,
544 osNode.intgBridge(),
545 sourceNatGateway.dataIp().getIp4Address()),
546 osNode.intgBridge())
Jian Li2d68c192018-12-13 15:52:59 +0900547 .setOutput(portNum);
Daniel Parkc64b4c62018-05-09 18:13:39 +0900548 break;
Daniel Parkc64b4c62018-05-09 18:13:39 +0900549 case VLAN:
Daniel Park51f9d1e2018-10-26 13:39:09 +0900550 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
Daniel Parkc64b4c62018-05-09 18:13:39 +0900551 tBuilder.setOutput(osNode.vlanPortNum());
552 break;
553
554 default:
555 break;
556 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900557
sanghodc375372017-06-08 10:41:30 +0900558 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900559 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900560 osNode.intgBridge(),
Daniel Parkc64b4c62018-05-09 18:13:39 +0900561 sBuilder.build(),
562 tBuilder.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900563 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900564 ROUTING_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900565 install);
566 }
567
Jian Li5ecfd1a2018-12-10 11:41:03 +0900568 private void setRouterAdminRules(String segmentId,
SONA Project6bc5c4a2018-12-14 23:49:52 +0900569 Type networkType,
Jian Li5ecfd1a2018-12-10 11:41:03 +0900570 boolean install) {
Frank Wang245a6822017-06-14 09:51:35 +0800571 TrafficTreatment treatment;
572 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
573 .matchEthType(Ethernet.TYPE_IPV4);
574
575 switch (networkType) {
576 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900577 case GRE:
Jian Li621f73c2018-12-15 01:49:22 +0900578 case GENEVE:
Frank Wang245a6822017-06-14 09:51:35 +0800579 sBuilder.matchTunnelId(Long.parseLong(segmentId));
580 break;
581 case VLAN:
582 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
583 break;
584 default:
Jian Li71670d12018-03-02 21:31:07 +0900585 final String error = String.format("%s %s",
586 ERR_UNSUPPORTED_NET_TYPE,
Frank Wang245a6822017-06-14 09:51:35 +0800587 networkType.toString());
588 throw new IllegalStateException(error);
589 }
590
591 treatment = DefaultTrafficTreatment.builder()
592 .drop()
593 .build();
594
595 osNodeService.completeNodes().stream()
596 .filter(osNode -> osNode.type() == COMPUTE)
597 .forEach(osNode -> {
598 osFlowRuleService.setRule(
599 appId,
600 osNode.intgBridge(),
601 sBuilder.build(),
602 treatment,
603 PRIORITY_ADMIN_RULE,
604 ROUTING_TABLE,
605 install);
606 });
607 }
608
Hyunsun Moon44aac662017-02-18 02:07:01 +0900609 private class InternalRouterEventListener implements OpenstackRouterListener {
610
Jian Li34220ea2018-11-14 01:30:24 +0900611 private boolean isRelevantHelper() {
612 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900613 }
614
Hyunsun Moon44aac662017-02-18 02:07:01 +0900615 @Override
616 public void event(OpenstackRouterEvent event) {
617 switch (event.type()) {
618 case OPENSTACK_ROUTER_CREATED:
Jian Li4d138702018-11-27 17:25:28 +0900619 eventExecutor.execute(() -> processRouterCreation(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900620 break;
621 case OPENSTACK_ROUTER_UPDATED:
Jian Li4d138702018-11-27 17:25:28 +0900622 eventExecutor.execute(() -> processRouterUpdate(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900623 break;
624 case OPENSTACK_ROUTER_REMOVED:
Jian Li4d138702018-11-27 17:25:28 +0900625 eventExecutor.execute(() -> processRouterRemoval(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900626 break;
627 case OPENSTACK_ROUTER_INTERFACE_ADDED:
Jian Li4d138702018-11-27 17:25:28 +0900628 eventExecutor.execute(() -> processRouterIntfCreation(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900629 break;
630 case OPENSTACK_ROUTER_INTERFACE_UPDATED:
Jian Li4d138702018-11-27 17:25:28 +0900631 eventExecutor.execute(() -> processRouterIntfUpdate(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900632 break;
633 case OPENSTACK_ROUTER_INTERFACE_REMOVED:
Jian Li4d138702018-11-27 17:25:28 +0900634 eventExecutor.execute(() -> processRouterIntfRemoval(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900635 break;
636 case OPENSTACK_ROUTER_GATEWAY_ADDED:
Jian Li32b03622018-11-06 17:54:24 +0900637 log.debug("Router external gateway {} added",
638 event.externalGateway().getNetworkId());
Ray Milkey08932a72018-02-20 15:34:38 -0800639 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900640 case OPENSTACK_ROUTER_GATEWAY_REMOVED:
Jian Li32b03622018-11-06 17:54:24 +0900641 log.debug("Router external gateway {} removed",
642 event.externalGateway().getNetworkId());
Ray Milkey08932a72018-02-20 15:34:38 -0800643 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900644 case OPENSTACK_FLOATING_IP_CREATED:
645 case OPENSTACK_FLOATING_IP_UPDATED:
646 case OPENSTACK_FLOATING_IP_REMOVED:
647 case OPENSTACK_FLOATING_IP_ASSOCIATED:
648 case OPENSTACK_FLOATING_IP_DISASSOCIATED:
649 default:
650 // do nothing for the other events
651 break;
652 }
653 }
Jian Li4d138702018-11-27 17:25:28 +0900654
655 private void processRouterCreation(OpenstackRouterEvent event) {
656 if (!isRelevantHelper()) {
657 return;
658 }
659
660 log.debug("Router(name:{}, ID:{}) is created",
661 event.subject().getName(),
662 event.subject().getId());
663
664 routerUpdated(event.subject());
665 }
666
667 private void processRouterUpdate(OpenstackRouterEvent event) {
668 if (!isRelevantHelper()) {
669 return;
670 }
671
672 log.debug("Router(name:{}, ID:{}) is updated",
673 event.subject().getName(),
674 event.subject().getId());
675
676 routerUpdated(event.subject());
677 }
678
679 private void processRouterRemoval(OpenstackRouterEvent event) {
680 if (!isRelevantHelper()) {
681 return;
682 }
683
684 log.debug("Router(name:{}, ID:{}) is removed",
685 event.subject().getName(),
686 event.subject().getId());
687
688 routerRemove(event.subject());
689 }
690
691 private void processRouterIntfCreation(OpenstackRouterEvent event) {
692 if (!isRelevantHelper()) {
693 return;
694 }
695
696 log.debug("Router interface {} added to router {}",
697 event.routerIface().getPortId(),
698 event.routerIface().getId());
699
700 routerIfaceAdded(event.subject(), event.routerIface());
701 }
702
703 private void processRouterIntfUpdate(OpenstackRouterEvent event) {
704 log.debug("Router interface {} on {} updated",
705 event.routerIface().getPortId(),
706 event.routerIface().getId());
707 }
708
709 private void processRouterIntfRemoval(OpenstackRouterEvent event) {
710 if (!isRelevantHelper()) {
711 return;
712 }
713
714 log.debug("Router interface {} removed from router {}",
715 event.routerIface().getPortId(),
716 event.routerIface().getId());
717
718 routerIfaceRemoved(event.subject(), event.routerIface());
719 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900720 }
721
722 private class InternalNodeEventListener implements OpenstackNodeListener {
723
Jian Li34220ea2018-11-14 01:30:24 +0900724 private boolean isRelevantHelper() {
725 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900726 }
727
728 @Override
729 public void event(OpenstackNodeEvent event) {
730 OpenstackNode osNode = event.subject();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900731 switch (event.type()) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900732 case OPENSTACK_NODE_COMPLETE:
733 case OPENSTACK_NODE_INCOMPLETE:
Daniel Park6ed9cf02018-06-27 19:07:44 +0900734 case OPENSTACK_NODE_UPDATED:
735 case OPENSTACK_NODE_REMOVED:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900736 eventExecutor.execute(() -> {
Jian Li34220ea2018-11-14 01:30:24 +0900737 if (!isRelevantHelper()) {
738 return;
739 }
Jian Li4d138702018-11-27 17:25:28 +0900740 reconfigureRouters(osNode);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900741 });
742 break;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900743 case OPENSTACK_NODE_CREATED:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900744 default:
745 break;
746 }
747 }
748
Jian Li4d138702018-11-27 17:25:28 +0900749 private void reconfigureRouters(OpenstackNode osNode) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900750 osRouterService.routers().forEach(osRouter -> {
751 routerUpdated(osRouter);
752 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
753 routerIfaceAdded(osRouter, iface);
754 });
755 });
Daniel Parkf8f4f202019-09-15 16:38:06 +0900756 log.debug("Reconfigure routers for {}", osNode.hostname());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900757 }
758 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900759}