blob: b825fc6e501f74922f995835ec76493a7d814cc2 [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;
Jian Li5b22f112020-10-05 22:36:41 +090082import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.deriveResourceName;
Jian Li25257212019-03-26 13:31:14 +090083import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValue;
84import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValueAsBoolean;
Jian Li2d68c192018-12-13 15:52:59 +090085import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.tunnelPortNumByNetType;
Jian Li26949762018-03-30 15:46:37 +090086import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
Hyunsun Moon0d457362017-06-27 17:19:41 +090087import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
88import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Hyunsun Moon44aac662017-02-18 02:07:01 +090089
90/**
91 * Handles OpenStack router events.
92 */
Jian Li33b4db52019-03-20 18:22:38 +090093@Component(immediate = true)
Hyunsun Moon44aac662017-02-18 02:07:01 +090094public class OpenstackRoutingHandler {
95
96 private final Logger log = LoggerFactory.getLogger(getClass());
97
98 private static final String MSG_ENABLED = "Enabled ";
99 private static final String MSG_DISABLED = "Disabled ";
daniel parkee8700b2017-05-11 15:50:03 +0900100 private static final String ERR_UNSUPPORTED_NET_TYPE = "Unsupported network type";
sanghoe765ce22017-06-23 17:54:57 +0900101
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700102 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900103 protected CoreService coreService;
104
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700105 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900106 protected LeadershipService leadershipService;
107
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700108 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900109 protected ClusterService clusterService;
110
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700111 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li25257212019-03-26 13:31:14 +0900112 protected ComponentConfigService configService;
113
114 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900115 protected OpenstackNodeService osNodeService;
116
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700117 @Reference(cardinality = ReferenceCardinality.MANDATORY)
daniel park32b42202018-03-14 16:53:44 +0900118 protected OpenstackNetworkAdminService osNetworkAdminService;
119
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700120 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900121 protected OpenstackRouterService osRouterService;
122
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700123 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho072c4dd2017-05-17 10:45:21 +0900124 protected InstancePortService instancePortService;
125
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700126 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho072c4dd2017-05-17 10:45:21 +0900127 protected DeviceService deviceService;
128
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700129 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sanghodc375372017-06-08 10:41:30 +0900130 protected OpenstackFlowRuleService osFlowRuleService;
131
Hyunsun Moon44aac662017-02-18 02:07:01 +0900132 private final ExecutorService eventExecutor = newSingleThreadScheduledExecutor(
133 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
134 private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
135 private final OpenstackRouterListener osRouterListener = new InternalRouterEventListener();
136
137 private ApplicationId appId;
138 private NodeId localNodeId;
139
140 @Activate
141 protected void activate() {
142 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
143 localNodeId = clusterService.getLocalNode().id();
144 leadershipService.runForLeadership(appId.name());
145 osNodeService.addListener(osNodeListener);
146 osRouterService.addListener(osRouterListener);
147
148 log.info("Started");
149 }
150
151 @Deactivate
152 protected void deactivate() {
153 osRouterService.removeListener(osRouterListener);
154 osNodeService.removeListener(osNodeListener);
155 leadershipService.withdraw(appId.name());
156 eventExecutor.shutdown();
157
158 log.info("Stopped");
159 }
160
161 private void routerUpdated(Router osRouter) {
Frank Wang245a6822017-06-14 09:51:35 +0800162 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
Jian Li5ecfd1a2018-12-10 11:41:03 +0900163 Network network = osNetworkAdminService.network(
164 osNetworkAdminService.subnet(iface.getSubnetId())
Frank Wang245a6822017-06-14 09:51:35 +0800165 .getNetworkId());
SONA Project6bc5c4a2018-12-14 23:49:52 +0900166 Type netType = osNetworkAdminService.networkType(
167 osNetworkAdminService.subnet(iface.getSubnetId())
168 .getNetworkId());
Jian Li5ecfd1a2018-12-10 11:41:03 +0900169 setRouterAdminRules(network.getProviderSegID(),
SONA Project6bc5c4a2018-12-14 23:49:52 +0900170 netType, !osRouter.isAdminStateUp());
Frank Wang245a6822017-06-14 09:51:35 +0800171 });
Daniel Park613ac372018-06-28 14:30:11 +0900172 }
173
Frank Wang245a6822017-06-14 09:51:35 +0800174 private void routerRemove(Router osRouter) {
175 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
Jian Li5ecfd1a2018-12-10 11:41:03 +0900176 Network network = osNetworkAdminService.network(
177 osNetworkAdminService.subnet(iface.getSubnetId())
Frank Wang245a6822017-06-14 09:51:35 +0800178 .getNetworkId());
SONA Project6bc5c4a2018-12-14 23:49:52 +0900179 Type netType = osNetworkAdminService.networkType(
180 osNetworkAdminService.subnet(iface.getSubnetId())
181 .getNetworkId());
182 setRouterAdminRules(network.getProviderSegID(), netType, false);
Frank Wang245a6822017-06-14 09:51:35 +0800183 });
184 }
185
Hyunsun Moon44aac662017-02-18 02:07:01 +0900186 private void routerIfaceAdded(Router osRouter, RouterInterface osRouterIface) {
Jian Liedc8b762018-03-22 15:42:00 +0900187 Subnet osSubnet = osNetworkAdminService.subnet(osRouterIface.getSubnetId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900188 if (osSubnet == null) {
189 final String error = String.format(
Jian Li71670d12018-03-02 21:31:07 +0900190 "Failed to set flows for router %s: subnet %s does not exist",
Hyunsun Moon44aac662017-02-18 02:07:01 +0900191 osRouterIface.getId(),
192 osRouterIface.getSubnetId());
193 throw new IllegalStateException(error);
194 }
Frank Wang245a6822017-06-14 09:51:35 +0800195
196 if (!osRouter.isAdminStateUp()) {
Jian Liedc8b762018-03-22 15:42:00 +0900197 Network network = osNetworkAdminService.network(osSubnet.getNetworkId());
SONA Project6bc5c4a2018-12-14 23:49:52 +0900198 Type netType = osNetworkAdminService.networkType(osSubnet.getNetworkId());
199 setRouterAdminRules(network.getProviderSegID(), netType, true);
Frank Wang245a6822017-06-14 09:51:35 +0800200 }
201
Hyunsun Moon44aac662017-02-18 02:07:01 +0900202 setInternalRoutes(osRouter, osSubnet, true);
Jian Li25257212019-03-26 13:31:14 +0900203 setGatewayRules(osSubnet, osRouter, true);
Jian Li5b22f112020-10-05 22:36:41 +0900204 log.info("Connected subnet({}) to {}", osSubnet.getCidr(), deriveResourceName(osRouter));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900205 }
206
207 private void routerIfaceRemoved(Router osRouter, RouterInterface osRouterIface) {
Jian Liedc8b762018-03-22 15:42:00 +0900208 Subnet osSubnet = osNetworkAdminService.subnet(osRouterIface.getSubnetId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900209 if (osSubnet == null) {
210 final String error = String.format(
Jian Li71670d12018-03-02 21:31:07 +0900211 "Failed to set flows for router %s: subnet %s does not exist",
Hyunsun Moon44aac662017-02-18 02:07:01 +0900212 osRouterIface.getId(),
213 osRouterIface.getSubnetId());
214 throw new IllegalStateException(error);
215 }
216
Frank Wang245a6822017-06-14 09:51:35 +0800217 if (!osRouter.isAdminStateUp()) {
Jian Liedc8b762018-03-22 15:42:00 +0900218 Network network = osNetworkAdminService.network(osSubnet.getNetworkId());
SONA Project6bc5c4a2018-12-14 23:49:52 +0900219 Type netType = osNetworkAdminService.networkType(osSubnet.getNetworkId());
220 setRouterAdminRules(network.getProviderSegID(), netType, false);
Frank Wang245a6822017-06-14 09:51:35 +0800221 }
222
Hyunsun Moon44aac662017-02-18 02:07:01 +0900223 setInternalRoutes(osRouter, osSubnet, false);
Jian Li25257212019-03-26 13:31:14 +0900224 setGatewayRules(osSubnet, osRouter, false);
Jian Li5b22f112020-10-05 22:36:41 +0900225 log.info("Disconnected subnet({}) from {}", osSubnet.getCidr(), deriveResourceName(osRouter));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900226 }
227
Jian Li25257212019-03-26 13:31:14 +0900228 private void setGatewayRules(Subnet osSubnet, Router osRouter, boolean install) {
Jian Li4d138702018-11-27 17:25:28 +0900229 OpenstackNode srcNatGw = osNodeService.completeNodes(GATEWAY)
230 .stream().findFirst().orElse(null);
daniel parkb5817102018-02-15 00:18:51 +0900231
Jian Li4d138702018-11-27 17:25:28 +0900232 if (srcNatGw == null) {
daniel parkb5817102018-02-15 00:18:51 +0900233 return;
234 }
235
Hyunsun Moon44aac662017-02-18 02:07:01 +0900236 if (Strings.isNullOrEmpty(osSubnet.getGateway())) {
237 // do nothing if no gateway is set
238 return;
239 }
240
Jian Li4d138702018-11-27 17:25:28 +0900241 Network net = osNetworkAdminService.network(osSubnet.getNetworkId());
Jian Li621f73c2018-12-15 01:49:22 +0900242 Type netType = osNetworkAdminService.networkType(osSubnet.getNetworkId());
Daniel Park51f9d1e2018-10-26 13:39:09 +0900243 Set<Subnet> routableSubnets = routableSubnets(osRouter, osSubnet.getId());
244
Jian Li25257212019-03-26 13:31:14 +0900245 // install rules to each compute node for routing IP packets to gateways
246 osNodeService.completeNodes(COMPUTE).stream()
247 .filter(cNode -> cNode.dataIp() != null)
248 .forEach(cNode -> setRulesToGatewayWithRoutableSubnets(
249 cNode,
250 srcNatGw,
251 net.getProviderSegID(),
252 osSubnet,
253 routableSubnets,
254 netType,
255 install));
256
Jian Lifdb8d872019-04-08 10:38:58 +0900257 // install rules to punt ICMP packets to controller at gateway node
258 // this rule is only valid for stateless ICMP SNAT case
259 osNodeService.completeNodes(GATEWAY).forEach(gNode ->
260 setReactiveGatewayIcmpRule(
261 IpAddress.valueOf(osSubnet.getGateway()),
262 gNode.intgBridge(), install));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900263
Hyunsun Moon44aac662017-02-18 02:07:01 +0900264 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
Jian Li25257212019-03-26 13:31:14 +0900265 log.debug(updateStr + "IP to {}", osSubnet.getGateway());
Jian Li4d138702018-11-27 17:25:28 +0900266 }
267
Hyunsun Moon44aac662017-02-18 02:07:01 +0900268 private void setInternalRoutes(Router osRouter, Subnet updatedSubnet, boolean install) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900269 Type netType = osNetworkAdminService.networkType(updatedSubnet.getNetworkId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900270 Set<Subnet> routableSubnets = routableSubnets(osRouter, updatedSubnet.getId());
Jian Lib6969502018-10-30 20:38:07 +0900271 String updatedSegmentId = getSegmentId(updatedSubnet);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900272
273 // installs rule from/to my subnet intentionally to fix ICMP failure
274 // to my subnet gateway if no external gateway added to the router
Hyunsun Moon0d457362017-06-27 17:19:41 +0900275 osNodeService.completeNodes(COMPUTE).forEach(cNode -> {
276 setInternalRouterRules(
277 cNode.intgBridge(),
Jian Lib6969502018-10-30 20:38:07 +0900278 updatedSegmentId,
279 updatedSegmentId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900280 IpPrefix.valueOf(updatedSubnet.getCidr()),
281 IpPrefix.valueOf(updatedSubnet.getCidr()),
SONA Project6bc5c4a2018-12-14 23:49:52 +0900282 netType,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900283 install
284 );
Hyunsun Moon44aac662017-02-18 02:07:01 +0900285
Hyunsun Moon0d457362017-06-27 17:19:41 +0900286 routableSubnets.forEach(subnet -> {
287 setInternalRouterRules(
288 cNode.intgBridge(),
Jian Lib6969502018-10-30 20:38:07 +0900289 updatedSegmentId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900290 getSegmentId(subnet),
291 IpPrefix.valueOf(updatedSubnet.getCidr()),
292 IpPrefix.valueOf(subnet.getCidr()),
SONA Project6bc5c4a2018-12-14 23:49:52 +0900293 netType,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900294 install
295 );
296 setInternalRouterRules(
297 cNode.intgBridge(),
298 getSegmentId(subnet),
Jian Lib6969502018-10-30 20:38:07 +0900299 updatedSegmentId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900300 IpPrefix.valueOf(subnet.getCidr()),
301 IpPrefix.valueOf(updatedSubnet.getCidr()),
SONA Project6bc5c4a2018-12-14 23:49:52 +0900302 netType,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900303 install
304 );
305 });
306 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900307
daniel parkee8700b2017-05-11 15:50:03 +0900308
Hyunsun Moon44aac662017-02-18 02:07:01 +0900309 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
310 routableSubnets.forEach(subnet -> log.debug(
311 updateStr + "route between subnet:{} and subnet:{}",
312 subnet.getCidr(),
313 updatedSubnet.getCidr()));
314 }
315
316 private Set<Subnet> routableSubnets(Router osRouter, String osSubnetId) {
317 Set<Subnet> osSubnets = osRouterService.routerInterfaces(osRouter.getId())
318 .stream()
319 .filter(iface -> !Objects.equals(iface.getSubnetId(), osSubnetId))
Jian Liedc8b762018-03-22 15:42:00 +0900320 .map(iface -> osNetworkAdminService.subnet(iface.getSubnetId()))
Hyunsun Moon44aac662017-02-18 02:07:01 +0900321 .collect(Collectors.toSet());
322 return ImmutableSet.copyOf(osSubnets);
323 }
324
daniel parkee8700b2017-05-11 15:50:03 +0900325 private String getSegmentId(Subnet osSubnet) {
Jian Liedc8b762018-03-22 15:42:00 +0900326 return osNetworkAdminService.network(osSubnet.getNetworkId()).getProviderSegID();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900327 }
328
Jian Li25257212019-03-26 13:31:14 +0900329 private boolean getStatefulSnatFlag() {
330 Set<ConfigProperty> properties = configService.getProperties(OpenstackRoutingSnatHandler.class.getName());
331 return getPropertyValueAsBoolean(properties, USE_STATEFUL_SNAT);
332 }
333
334 private String getArpMode() {
335 Set<ConfigProperty> properties = configService.getProperties(OpenstackRoutingArpHandler.class.getName());
336 return getPropertyValue(properties, ARP_MODE);
337 }
338
339 private void setReactiveGatewayIcmpRule(IpAddress gatewayIp, DeviceId deviceId, boolean install) {
Jian Lifdb8d872019-04-08 10:38:58 +0900340
341 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
342 int icmpRulePriority;
343
344 if (getStatefulSnatFlag()) {
345 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
346 .matchIPProtocol(IPv4.PROTOCOL_ICMP)
347 .matchIcmpType(ICMP.TYPE_ECHO_REQUEST);
348 icmpRulePriority = PRIORITY_ICMP_REQUEST_RULE;
349 } else {
350 sBuilder.matchEthType(Ethernet.TYPE_IPV4)
351 .matchIPProtocol(IPv4.PROTOCOL_ICMP)
352 .matchIPDst(gatewayIp.getIp4Address().toIpPrefix());
353 icmpRulePriority = PRIORITY_ICMP_RULE;
354 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900355
356 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Li4d5c5c32018-04-02 16:38:18 +0900357 .punt()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900358 .build();
359
sanghodc375372017-06-08 10:41:30 +0900360 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900361 appId,
362 deviceId,
Jian Lifdb8d872019-04-08 10:38:58 +0900363 sBuilder.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900364 treatment,
Jian Lifdb8d872019-04-08 10:38:58 +0900365 icmpRulePriority,
sanghodc375372017-06-08 10:41:30 +0900366 Constants.GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900367 install);
368 }
369
Jian Li4d138702018-11-27 17:25:28 +0900370 private void setInternalRouterRules(DeviceId deviceId, String srcSegId, String dstSegId,
daniel parkee8700b2017-05-11 15:50:03 +0900371 IpPrefix srcSubnet, IpPrefix dstSubnet,
SONA Project6bc5c4a2018-12-14 23:49:52 +0900372 Type networkType, boolean install) {
Jian Li4d138702018-11-27 17:25:28 +0900373
daniel parkee8700b2017-05-11 15:50:03 +0900374 switch (networkType) {
375 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900376 case GRE:
Jian Li621f73c2018-12-15 01:49:22 +0900377 case GENEVE:
Jian Li2d68c192018-12-13 15:52:59 +0900378 setInternalRouterRulesForTunnel(deviceId, srcSegId, dstSegId,
Jian Li4d138702018-11-27 17:25:28 +0900379 srcSubnet, dstSubnet, install);
daniel parkee8700b2017-05-11 15:50:03 +0900380 break;
381 case VLAN:
Jian Li4d138702018-11-27 17:25:28 +0900382 setInternalRouterRulesForVlan(deviceId, srcSegId, dstSegId,
383 srcSubnet, dstSubnet, install);
daniel parkee8700b2017-05-11 15:50:03 +0900384 break;
385 default:
Jian Li4d138702018-11-27 17:25:28 +0900386 final String error = String.format("%s %s", ERR_UNSUPPORTED_NET_TYPE,
387 networkType.toString());
daniel parkee8700b2017-05-11 15:50:03 +0900388 throw new IllegalStateException(error);
389 }
390
Hyunsun Moon44aac662017-02-18 02:07:01 +0900391 }
392
Jian Li2d68c192018-12-13 15:52:59 +0900393 private void setInternalRouterRulesForTunnel(DeviceId deviceId,
394 String srcSegmentId,
395 String dstSegmentId,
396 IpPrefix srcSubnet,
397 IpPrefix dstSubnet,
398 boolean install) {
Jian Li4d138702018-11-27 17:25:28 +0900399 TrafficSelector selector;
400 TrafficTreatment treatment;
401 selector = DefaultTrafficSelector.builder()
402 .matchEthType(Ethernet.TYPE_IPV4)
403 .matchTunnelId(Long.parseLong(srcSegmentId))
404 .matchIPSrc(srcSubnet.getIp4Prefix())
405 .matchIPDst(dstSubnet.getIp4Prefix())
406 .build();
407
408 treatment = DefaultTrafficTreatment.builder()
409 .setTunnelId(Long.parseLong(dstSegmentId))
410 .transition(STAT_OUTBOUND_TABLE)
411 .build();
412
413 osFlowRuleService.setRule(
414 appId,
415 deviceId,
416 selector,
417 treatment,
418 PRIORITY_INTERNAL_ROUTING_RULE,
419 ROUTING_TABLE,
420 install);
421
422 selector = DefaultTrafficSelector.builder()
423 .matchEthType(Ethernet.TYPE_IPV4)
424 .matchTunnelId(Long.parseLong(dstSegmentId))
425 .matchIPSrc(srcSubnet.getIp4Prefix())
426 .matchIPDst(dstSubnet.getIp4Prefix())
427 .build();
428
429 treatment = DefaultTrafficTreatment.builder()
430 .setTunnelId(Long.parseLong(dstSegmentId))
431 .transition(STAT_OUTBOUND_TABLE)
432 .build();
433
434 osFlowRuleService.setRule(
435 appId,
436 deviceId,
437 selector,
438 treatment,
439 PRIORITY_INTERNAL_ROUTING_RULE,
440 ROUTING_TABLE,
441 install);
442 }
443
444 private void setInternalRouterRulesForVlan(DeviceId deviceId,
445 String srcSegmentId,
446 String dstSegmentId,
447 IpPrefix srcSubnet,
448 IpPrefix dstSubnet,
449 boolean install) {
450 TrafficSelector selector;
451 TrafficTreatment treatment;
452 selector = DefaultTrafficSelector.builder()
453 .matchEthType(Ethernet.TYPE_IPV4)
454 .matchVlanId(VlanId.vlanId(srcSegmentId))
455 .matchIPSrc(srcSubnet.getIp4Prefix())
456 .matchIPDst(dstSubnet.getIp4Prefix())
457 .build();
458
459 treatment = DefaultTrafficTreatment.builder()
460 .setVlanId(VlanId.vlanId(dstSegmentId))
461 .transition(STAT_OUTBOUND_TABLE)
462 .build();
463
464 osFlowRuleService.setRule(
465 appId,
466 deviceId,
467 selector,
468 treatment,
469 PRIORITY_INTERNAL_ROUTING_RULE,
470 ROUTING_TABLE,
471 install);
472
473 selector = DefaultTrafficSelector.builder()
474 .matchEthType(Ethernet.TYPE_IPV4)
475 .matchVlanId(VlanId.vlanId(dstSegmentId))
476 .matchIPSrc(srcSubnet.getIp4Prefix())
477 .matchIPDst(dstSubnet.getIp4Prefix())
478 .build();
479
480 treatment = DefaultTrafficTreatment.builder()
481 .setVlanId(VlanId.vlanId(dstSegmentId))
482 .transition(STAT_OUTBOUND_TABLE)
483 .build();
484
485 osFlowRuleService.setRule(
486 appId,
487 deviceId,
488 selector,
489 treatment,
490 PRIORITY_INTERNAL_ROUTING_RULE,
491 ROUTING_TABLE,
492 install);
493 }
494
Jian Li5ecfd1a2018-12-10 11:41:03 +0900495 private void setRulesToGatewayWithRoutableSubnets(OpenstackNode osNode,
496 OpenstackNode sourceNatGateway,
497 String segmentId,
498 Subnet updatedSubnet,
499 Set<Subnet> routableSubnets,
SONA Project6bc5c4a2018-12-14 23:49:52 +0900500 Type networkType,
Daniel Park51f9d1e2018-10-26 13:39:09 +0900501 boolean install) {
Jian Li25257212019-03-26 13:31:14 +0900502
503 if (getStatefulSnatFlag() && ARP_BROADCAST_MODE.equals(getArpMode())) {
504 return;
505 }
506
507 // at first we install flow rules to gateway with segId and gatewayIp of updated subnet
Jian Li5ecfd1a2018-12-10 11:41:03 +0900508 setRulesToGatewayWithDstIp(osNode, sourceNatGateway, segmentId,
Jian Li2d68c192018-12-13 15:52:59 +0900509 IpAddress.valueOf(updatedSubnet.getGateway()), networkType, install);
Daniel Park51f9d1e2018-10-26 13:39:09 +0900510
511 routableSubnets.forEach(subnet -> {
512 setRulesToGatewayWithDstIp(osNode, sourceNatGateway,
513 segmentId, IpAddress.valueOf(subnet.getGateway()),
Jian Li2d68c192018-12-13 15:52:59 +0900514 networkType, install);
Daniel Park51f9d1e2018-10-26 13:39:09 +0900515
516 Network network = osNetworkAdminService.network(subnet.getNetworkId());
517 setRulesToGatewayWithDstIp(osNode, sourceNatGateway,
518 network.getProviderSegID(), IpAddress.valueOf(updatedSubnet.getGateway()),
Jian Li2d68c192018-12-13 15:52:59 +0900519 networkType, install);
Daniel Park51f9d1e2018-10-26 13:39:09 +0900520 });
521 }
522
Jian Li5ecfd1a2018-12-10 11:41:03 +0900523 private void setRulesToGatewayWithDstIp(OpenstackNode osNode,
524 OpenstackNode sourceNatGateway,
525 String segmentId,
526 IpAddress dstIp,
SONA Project6bc5c4a2018-12-14 23:49:52 +0900527 Type networkType,
Jian Li5ecfd1a2018-12-10 11:41:03 +0900528 boolean install) {
Daniel Parkc64b4c62018-05-09 18:13:39 +0900529 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
530 .matchEthType(Ethernet.TYPE_IPV4)
531 .matchIPDst(dstIp.getIp4Address().toIpPrefix());
532
Daniel Parkc64b4c62018-05-09 18:13:39 +0900533 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
534
Jian Li2d68c192018-12-13 15:52:59 +0900535 switch (networkType) {
Daniel Parkc64b4c62018-05-09 18:13:39 +0900536 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900537 case GRE:
Jian Li621f73c2018-12-15 01:49:22 +0900538 case GENEVE:
Daniel Park51f9d1e2018-10-26 13:39:09 +0900539 sBuilder.matchTunnelId(Long.parseLong(segmentId));
Jian Li2d68c192018-12-13 15:52:59 +0900540
SONA Project6bc5c4a2018-12-14 23:49:52 +0900541 PortNumber portNum = tunnelPortNumByNetType(networkType, osNode);
Jian Li2d68c192018-12-13 15:52:59 +0900542
Daniel Parkc64b4c62018-05-09 18:13:39 +0900543 tBuilder.extension(buildExtension(
daniel parkb5817102018-02-15 00:18:51 +0900544 deviceService,
545 osNode.intgBridge(),
546 sourceNatGateway.dataIp().getIp4Address()),
547 osNode.intgBridge())
Jian Li2d68c192018-12-13 15:52:59 +0900548 .setOutput(portNum);
Daniel Parkc64b4c62018-05-09 18:13:39 +0900549 break;
Daniel Parkc64b4c62018-05-09 18:13:39 +0900550 case VLAN:
Daniel Park51f9d1e2018-10-26 13:39:09 +0900551 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
Daniel Parkc64b4c62018-05-09 18:13:39 +0900552 tBuilder.setOutput(osNode.vlanPortNum());
553 break;
554
555 default:
556 break;
557 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900558
sanghodc375372017-06-08 10:41:30 +0900559 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900560 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900561 osNode.intgBridge(),
Daniel Parkc64b4c62018-05-09 18:13:39 +0900562 sBuilder.build(),
563 tBuilder.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900564 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900565 ROUTING_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900566 install);
567 }
568
Jian Li5ecfd1a2018-12-10 11:41:03 +0900569 private void setRouterAdminRules(String segmentId,
SONA Project6bc5c4a2018-12-14 23:49:52 +0900570 Type networkType,
Jian Li5ecfd1a2018-12-10 11:41:03 +0900571 boolean install) {
Frank Wang245a6822017-06-14 09:51:35 +0800572 TrafficTreatment treatment;
573 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
574 .matchEthType(Ethernet.TYPE_IPV4);
575
576 switch (networkType) {
577 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900578 case GRE:
Jian Li621f73c2018-12-15 01:49:22 +0900579 case GENEVE:
Frank Wang245a6822017-06-14 09:51:35 +0800580 sBuilder.matchTunnelId(Long.parseLong(segmentId));
581 break;
582 case VLAN:
583 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
584 break;
585 default:
Jian Li71670d12018-03-02 21:31:07 +0900586 final String error = String.format("%s %s",
587 ERR_UNSUPPORTED_NET_TYPE,
Frank Wang245a6822017-06-14 09:51:35 +0800588 networkType.toString());
589 throw new IllegalStateException(error);
590 }
591
592 treatment = DefaultTrafficTreatment.builder()
593 .drop()
594 .build();
595
596 osNodeService.completeNodes().stream()
597 .filter(osNode -> osNode.type() == COMPUTE)
598 .forEach(osNode -> {
599 osFlowRuleService.setRule(
600 appId,
601 osNode.intgBridge(),
602 sBuilder.build(),
603 treatment,
604 PRIORITY_ADMIN_RULE,
605 ROUTING_TABLE,
606 install);
607 });
608 }
609
Hyunsun Moon44aac662017-02-18 02:07:01 +0900610 private class InternalRouterEventListener implements OpenstackRouterListener {
611
Jian Li34220ea2018-11-14 01:30:24 +0900612 private boolean isRelevantHelper() {
613 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900614 }
615
Hyunsun Moon44aac662017-02-18 02:07:01 +0900616 @Override
617 public void event(OpenstackRouterEvent event) {
618 switch (event.type()) {
619 case OPENSTACK_ROUTER_CREATED:
Jian Li4d138702018-11-27 17:25:28 +0900620 eventExecutor.execute(() -> processRouterCreation(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900621 break;
622 case OPENSTACK_ROUTER_UPDATED:
Jian Li4d138702018-11-27 17:25:28 +0900623 eventExecutor.execute(() -> processRouterUpdate(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900624 break;
625 case OPENSTACK_ROUTER_REMOVED:
Jian Li4d138702018-11-27 17:25:28 +0900626 eventExecutor.execute(() -> processRouterRemoval(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900627 break;
628 case OPENSTACK_ROUTER_INTERFACE_ADDED:
Jian Li4d138702018-11-27 17:25:28 +0900629 eventExecutor.execute(() -> processRouterIntfCreation(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900630 break;
631 case OPENSTACK_ROUTER_INTERFACE_UPDATED:
Jian Li4d138702018-11-27 17:25:28 +0900632 eventExecutor.execute(() -> processRouterIntfUpdate(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900633 break;
634 case OPENSTACK_ROUTER_INTERFACE_REMOVED:
Jian Li4d138702018-11-27 17:25:28 +0900635 eventExecutor.execute(() -> processRouterIntfRemoval(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900636 break;
637 case OPENSTACK_ROUTER_GATEWAY_ADDED:
Jian Li32b03622018-11-06 17:54:24 +0900638 log.debug("Router external gateway {} added",
639 event.externalGateway().getNetworkId());
Ray Milkey08932a72018-02-20 15:34:38 -0800640 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900641 case OPENSTACK_ROUTER_GATEWAY_REMOVED:
Jian Li32b03622018-11-06 17:54:24 +0900642 log.debug("Router external gateway {} removed",
643 event.externalGateway().getNetworkId());
Ray Milkey08932a72018-02-20 15:34:38 -0800644 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900645 case OPENSTACK_FLOATING_IP_CREATED:
646 case OPENSTACK_FLOATING_IP_UPDATED:
647 case OPENSTACK_FLOATING_IP_REMOVED:
648 case OPENSTACK_FLOATING_IP_ASSOCIATED:
649 case OPENSTACK_FLOATING_IP_DISASSOCIATED:
650 default:
651 // do nothing for the other events
652 break;
653 }
654 }
Jian Li4d138702018-11-27 17:25:28 +0900655
656 private void processRouterCreation(OpenstackRouterEvent event) {
657 if (!isRelevantHelper()) {
658 return;
659 }
660
661 log.debug("Router(name:{}, ID:{}) is created",
Jian Li5b22f112020-10-05 22:36:41 +0900662 deriveResourceName(event.subject()), event.subject().getId());
Jian Li4d138702018-11-27 17:25:28 +0900663
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",
Jian Li5b22f112020-10-05 22:36:41 +0900673 deriveResourceName(event.subject()), event.subject().getId());
Jian Li4d138702018-11-27 17:25:28 +0900674
675 routerUpdated(event.subject());
676 }
677
678 private void processRouterRemoval(OpenstackRouterEvent event) {
679 if (!isRelevantHelper()) {
680 return;
681 }
682
683 log.debug("Router(name:{}, ID:{}) is removed",
Jian Li5b22f112020-10-05 22:36:41 +0900684 deriveResourceName(event.subject()), event.subject().getId());
Jian Li4d138702018-11-27 17:25:28 +0900685
686 routerRemove(event.subject());
687 }
688
689 private void processRouterIntfCreation(OpenstackRouterEvent event) {
690 if (!isRelevantHelper()) {
691 return;
692 }
693
694 log.debug("Router interface {} added to router {}",
695 event.routerIface().getPortId(),
696 event.routerIface().getId());
697
698 routerIfaceAdded(event.subject(), event.routerIface());
699 }
700
701 private void processRouterIntfUpdate(OpenstackRouterEvent event) {
702 log.debug("Router interface {} on {} updated",
703 event.routerIface().getPortId(),
704 event.routerIface().getId());
705 }
706
707 private void processRouterIntfRemoval(OpenstackRouterEvent event) {
708 if (!isRelevantHelper()) {
709 return;
710 }
711
712 log.debug("Router interface {} removed from router {}",
713 event.routerIface().getPortId(),
714 event.routerIface().getId());
715
716 routerIfaceRemoved(event.subject(), event.routerIface());
717 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900718 }
719
720 private class InternalNodeEventListener implements OpenstackNodeListener {
721
Jian Li34220ea2018-11-14 01:30:24 +0900722 private boolean isRelevantHelper() {
723 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900724 }
725
726 @Override
727 public void event(OpenstackNodeEvent event) {
728 OpenstackNode osNode = event.subject();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900729 switch (event.type()) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900730 case OPENSTACK_NODE_COMPLETE:
Daniel Park6ed9cf02018-06-27 19:07:44 +0900731 case OPENSTACK_NODE_UPDATED:
732 case OPENSTACK_NODE_REMOVED:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900733 eventExecutor.execute(() -> {
Jian Li34220ea2018-11-14 01:30:24 +0900734 if (!isRelevantHelper()) {
735 return;
736 }
Jian Li4d138702018-11-27 17:25:28 +0900737 reconfigureRouters(osNode);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900738 });
739 break;
Jian Lif7f01d12019-09-24 22:32:02 +0900740 case OPENSTACK_NODE_INCOMPLETE:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900741 case OPENSTACK_NODE_CREATED:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900742 default:
743 break;
744 }
745 }
746
Jian Li4d138702018-11-27 17:25:28 +0900747 private void reconfigureRouters(OpenstackNode osNode) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900748 osRouterService.routers().forEach(osRouter -> {
749 routerUpdated(osRouter);
750 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
751 routerIfaceAdded(osRouter, iface);
752 });
753 });
Daniel Parkf8f4f202019-09-15 16:38:06 +0900754 log.debug("Reconfigure routers for {}", osNode.hostname());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900755 }
756 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900757}