blob: 96a2c5b8cbf61f63a14e2380cbe3a72711b4f6af [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;
21import org.onlab.packet.IPv4;
22import org.onlab.packet.IpAddress;
23import org.onlab.packet.IpPrefix;
daniel parkee8700b2017-05-11 15:50:03 +090024import org.onlab.packet.VlanId;
Hyunsun Moon44aac662017-02-18 02:07:01 +090025import org.onosproject.cluster.ClusterService;
26import org.onosproject.cluster.LeadershipService;
27import org.onosproject.cluster.NodeId;
28import org.onosproject.core.ApplicationId;
29import org.onosproject.core.CoreService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090030import org.onosproject.net.DeviceId;
31import org.onosproject.net.PortNumber;
sangho072c4dd2017-05-17 10:45:21 +090032import org.onosproject.net.device.DeviceService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090033import org.onosproject.net.flow.DefaultTrafficSelector;
34import org.onosproject.net.flow.DefaultTrafficTreatment;
35import org.onosproject.net.flow.TrafficSelector;
36import org.onosproject.net.flow.TrafficTreatment;
Hyunsun Moon44aac662017-02-18 02:07:01 +090037import org.onosproject.openstacknetworking.api.Constants;
sangho072c4dd2017-05-17 10:45:21 +090038import org.onosproject.openstacknetworking.api.InstancePortService;
sanghodc375372017-06-08 10:41:30 +090039import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
SONA Project6bc5c4a2018-12-14 23:49:52 +090040import org.onosproject.openstacknetworking.api.OpenstackNetwork.Type;
daniel park32b42202018-03-14 16:53:44 +090041import org.onosproject.openstacknetworking.api.OpenstackNetworkAdminService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090042import org.onosproject.openstacknetworking.api.OpenstackRouterEvent;
43import org.onosproject.openstacknetworking.api.OpenstackRouterListener;
44import org.onosproject.openstacknetworking.api.OpenstackRouterService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090045import org.onosproject.openstacknode.api.OpenstackNode;
Hyunsun Moon0d457362017-06-27 17:19:41 +090046import org.onosproject.openstacknode.api.OpenstackNodeEvent;
47import org.onosproject.openstacknode.api.OpenstackNodeListener;
48import org.onosproject.openstacknode.api.OpenstackNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090049import org.openstack4j.model.network.Network;
50import org.openstack4j.model.network.Router;
51import org.openstack4j.model.network.RouterInterface;
52import org.openstack4j.model.network.Subnet;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070053import org.osgi.service.component.annotations.Activate;
54import org.osgi.service.component.annotations.Component;
55import org.osgi.service.component.annotations.Deactivate;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070056import org.osgi.service.component.annotations.Reference;
57import org.osgi.service.component.annotations.ReferenceCardinality;
Hyunsun Moon44aac662017-02-18 02:07:01 +090058import org.slf4j.Logger;
59import org.slf4j.LoggerFactory;
60
61import java.util.Objects;
62import java.util.Set;
63import java.util.concurrent.ExecutorService;
64import java.util.stream.Collectors;
65
66import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
67import static org.onlab.util.Tools.groupedThreads;
sangho072c4dd2017-05-17 10:45:21 +090068import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
daniel park796c2eb2018-03-22 17:01:51 +090069import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ADMIN_RULE;
sangho072c4dd2017-05-17 10:45:21 +090070import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ICMP_RULE;
71import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_INTERNAL_ROUTING_RULE;
sangho072c4dd2017-05-17 10:45:21 +090072import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_SWITCHING_RULE;
73import static org.onosproject.openstacknetworking.api.Constants.ROUTING_TABLE;
Jian Li8abf2fe2018-06-12 18:42:30 +090074import static org.onosproject.openstacknetworking.api.Constants.STAT_OUTBOUND_TABLE;
Jian Li621f73c2018-12-15 01:49:22 +090075import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.GENEVE;
76import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.GRE;
SONA Project6bc5c4a2018-12-14 23:49:52 +090077import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.VLAN;
Jian Li621f73c2018-12-15 01:49:22 +090078import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.VXLAN;
Jian Li2d68c192018-12-13 15:52:59 +090079import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.tunnelPortNumByNetType;
Jian Li26949762018-03-30 15:46:37 +090080import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
Hyunsun Moon0d457362017-06-27 17:19:41 +090081import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
82import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Hyunsun Moon44aac662017-02-18 02:07:01 +090083
84/**
85 * Handles OpenStack router events.
86 */
Jian Li33b4db52019-03-20 18:22:38 +090087@Component(immediate = true)
Hyunsun Moon44aac662017-02-18 02:07:01 +090088public class OpenstackRoutingHandler {
89
90 private final Logger log = LoggerFactory.getLogger(getClass());
91
92 private static final String MSG_ENABLED = "Enabled ";
93 private static final String MSG_DISABLED = "Disabled ";
daniel parkee8700b2017-05-11 15:50:03 +090094 private static final String ERR_UNSUPPORTED_NET_TYPE = "Unsupported network type";
sanghoe765ce22017-06-23 17:54:57 +090095
Ray Milkeyd84f89b2018-08-17 14:54:17 -070096 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +090097 protected CoreService coreService;
98
Ray Milkeyd84f89b2018-08-17 14:54:17 -070099 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900100 protected LeadershipService leadershipService;
101
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700102 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900103 protected ClusterService clusterService;
104
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700105 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900106 protected OpenstackNodeService osNodeService;
107
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700108 @Reference(cardinality = ReferenceCardinality.MANDATORY)
daniel park32b42202018-03-14 16:53:44 +0900109 protected OpenstackNetworkAdminService osNetworkAdminService;
110
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700111 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900112 protected OpenstackRouterService osRouterService;
113
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700114 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho072c4dd2017-05-17 10:45:21 +0900115 protected InstancePortService instancePortService;
116
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700117 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sangho072c4dd2017-05-17 10:45:21 +0900118 protected DeviceService deviceService;
119
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700120 @Reference(cardinality = ReferenceCardinality.MANDATORY)
sanghodc375372017-06-08 10:41:30 +0900121 protected OpenstackFlowRuleService osFlowRuleService;
122
Hyunsun Moon44aac662017-02-18 02:07:01 +0900123 private final ExecutorService eventExecutor = newSingleThreadScheduledExecutor(
124 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
125 private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
126 private final OpenstackRouterListener osRouterListener = new InternalRouterEventListener();
127
128 private ApplicationId appId;
129 private NodeId localNodeId;
130
131 @Activate
132 protected void activate() {
133 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
134 localNodeId = clusterService.getLocalNode().id();
135 leadershipService.runForLeadership(appId.name());
136 osNodeService.addListener(osNodeListener);
137 osRouterService.addListener(osRouterListener);
138
139 log.info("Started");
140 }
141
142 @Deactivate
143 protected void deactivate() {
144 osRouterService.removeListener(osRouterListener);
145 osNodeService.removeListener(osNodeListener);
146 leadershipService.withdraw(appId.name());
147 eventExecutor.shutdown();
148
149 log.info("Stopped");
150 }
151
152 private void routerUpdated(Router osRouter) {
Frank Wang245a6822017-06-14 09:51:35 +0800153 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
Jian Li5ecfd1a2018-12-10 11:41:03 +0900154 Network network = osNetworkAdminService.network(
155 osNetworkAdminService.subnet(iface.getSubnetId())
Frank Wang245a6822017-06-14 09:51:35 +0800156 .getNetworkId());
SONA Project6bc5c4a2018-12-14 23:49:52 +0900157 Type netType = osNetworkAdminService.networkType(
158 osNetworkAdminService.subnet(iface.getSubnetId())
159 .getNetworkId());
Jian Li5ecfd1a2018-12-10 11:41:03 +0900160 setRouterAdminRules(network.getProviderSegID(),
SONA Project6bc5c4a2018-12-14 23:49:52 +0900161 netType, !osRouter.isAdminStateUp());
Frank Wang245a6822017-06-14 09:51:35 +0800162 });
Daniel Park613ac372018-06-28 14:30:11 +0900163 }
164
Frank Wang245a6822017-06-14 09:51:35 +0800165 private void routerRemove(Router osRouter) {
166 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
Jian Li5ecfd1a2018-12-10 11:41:03 +0900167 Network network = osNetworkAdminService.network(
168 osNetworkAdminService.subnet(iface.getSubnetId())
Frank Wang245a6822017-06-14 09:51:35 +0800169 .getNetworkId());
SONA Project6bc5c4a2018-12-14 23:49:52 +0900170 Type netType = osNetworkAdminService.networkType(
171 osNetworkAdminService.subnet(iface.getSubnetId())
172 .getNetworkId());
173 setRouterAdminRules(network.getProviderSegID(), netType, false);
Frank Wang245a6822017-06-14 09:51:35 +0800174 });
175 }
176
Hyunsun Moon44aac662017-02-18 02:07:01 +0900177 private void routerIfaceAdded(Router osRouter, RouterInterface osRouterIface) {
Jian Liedc8b762018-03-22 15:42:00 +0900178 Subnet osSubnet = osNetworkAdminService.subnet(osRouterIface.getSubnetId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900179 if (osSubnet == null) {
180 final String error = String.format(
Jian Li71670d12018-03-02 21:31:07 +0900181 "Failed to set flows for router %s: subnet %s does not exist",
Hyunsun Moon44aac662017-02-18 02:07:01 +0900182 osRouterIface.getId(),
183 osRouterIface.getSubnetId());
184 throw new IllegalStateException(error);
185 }
Frank Wang245a6822017-06-14 09:51:35 +0800186
187 if (!osRouter.isAdminStateUp()) {
Jian Liedc8b762018-03-22 15:42:00 +0900188 Network network = osNetworkAdminService.network(osSubnet.getNetworkId());
SONA Project6bc5c4a2018-12-14 23:49:52 +0900189 Type netType = osNetworkAdminService.networkType(osSubnet.getNetworkId());
190 setRouterAdminRules(network.getProviderSegID(), netType, true);
Frank Wang245a6822017-06-14 09:51:35 +0800191 }
192
Hyunsun Moon44aac662017-02-18 02:07:01 +0900193 setInternalRoutes(osRouter, osSubnet, true);
Daniel Park51f9d1e2018-10-26 13:39:09 +0900194 setGatewayIcmp(osSubnet, osRouter, true);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900195 log.info("Connected subnet({}) to {}", osSubnet.getCidr(), osRouter.getName());
196 }
197
198 private void routerIfaceRemoved(Router osRouter, RouterInterface osRouterIface) {
Jian Liedc8b762018-03-22 15:42:00 +0900199 Subnet osSubnet = osNetworkAdminService.subnet(osRouterIface.getSubnetId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900200 if (osSubnet == null) {
201 final String error = String.format(
Jian Li71670d12018-03-02 21:31:07 +0900202 "Failed to set flows for router %s: subnet %s does not exist",
Hyunsun Moon44aac662017-02-18 02:07:01 +0900203 osRouterIface.getId(),
204 osRouterIface.getSubnetId());
205 throw new IllegalStateException(error);
206 }
207
Frank Wang245a6822017-06-14 09:51:35 +0800208 if (!osRouter.isAdminStateUp()) {
Jian Liedc8b762018-03-22 15:42:00 +0900209 Network network = osNetworkAdminService.network(osSubnet.getNetworkId());
SONA Project6bc5c4a2018-12-14 23:49:52 +0900210 Type netType = osNetworkAdminService.networkType(osSubnet.getNetworkId());
211 setRouterAdminRules(network.getProviderSegID(), netType, false);
Frank Wang245a6822017-06-14 09:51:35 +0800212 }
213
Hyunsun Moon44aac662017-02-18 02:07:01 +0900214 setInternalRoutes(osRouter, osSubnet, false);
Daniel Park51f9d1e2018-10-26 13:39:09 +0900215 setGatewayIcmp(osSubnet, osRouter, false);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900216 log.info("Disconnected subnet({}) from {}", osSubnet.getCidr(), osRouter.getName());
217 }
218
Daniel Park51f9d1e2018-10-26 13:39:09 +0900219 private void setGatewayIcmp(Subnet osSubnet, Router osRouter, boolean install) {
Jian Li4d138702018-11-27 17:25:28 +0900220 OpenstackNode srcNatGw = osNodeService.completeNodes(GATEWAY)
221 .stream().findFirst().orElse(null);
daniel parkb5817102018-02-15 00:18:51 +0900222
Jian Li4d138702018-11-27 17:25:28 +0900223 if (srcNatGw == null) {
daniel parkb5817102018-02-15 00:18:51 +0900224 return;
225 }
226
Hyunsun Moon44aac662017-02-18 02:07:01 +0900227 if (Strings.isNullOrEmpty(osSubnet.getGateway())) {
228 // do nothing if no gateway is set
229 return;
230 }
231
232 // take ICMP request to a subnet gateway through gateway node group
Jian Li4d138702018-11-27 17:25:28 +0900233 Network net = osNetworkAdminService.network(osSubnet.getNetworkId());
Jian Li621f73c2018-12-15 01:49:22 +0900234 Type netType = osNetworkAdminService.networkType(osSubnet.getNetworkId());
Daniel Park51f9d1e2018-10-26 13:39:09 +0900235 Set<Subnet> routableSubnets = routableSubnets(osRouter, osSubnet.getId());
236
Jian Li621f73c2018-12-15 01:49:22 +0900237 switch (netType) {
daniel parkee8700b2017-05-11 15:50:03 +0900238 case VXLAN:
Jian Li4d138702018-11-27 17:25:28 +0900239 setGatewayIcmpForVxlan(osSubnet, srcNatGw, net, routableSubnets, install);
daniel parkee8700b2017-05-11 15:50:03 +0900240 break;
Jian Li2d68c192018-12-13 15:52:59 +0900241 case GRE:
242 setGatewayIcmpForGre(osSubnet, srcNatGw, net, routableSubnets, install);
243 break;
Jian Li621f73c2018-12-15 01:49:22 +0900244 case GENEVE:
245 setGatewayIcmpForGeneve(osSubnet, srcNatGw, net, routableSubnets, install);
246 break;
daniel parkee8700b2017-05-11 15:50:03 +0900247 case VLAN:
Jian Li4d138702018-11-27 17:25:28 +0900248 setGatewayIcmpForVlan(osSubnet, srcNatGw, net, routableSubnets, install);
daniel parkee8700b2017-05-11 15:50:03 +0900249 break;
250 default:
Jian Li4d138702018-11-27 17:25:28 +0900251 final String error = String.format("%s %s", ERR_UNSUPPORTED_NET_TYPE,
Jian Li621f73c2018-12-15 01:49:22 +0900252 netType.toString());
daniel parkee8700b2017-05-11 15:50:03 +0900253 throw new IllegalStateException(error);
254 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900255
256 IpAddress gatewayIp = IpAddress.valueOf(osSubnet.getGateway());
daniel park576969a2018-03-09 07:07:41 +0900257 osNodeService.completeNodes(GATEWAY).forEach(gNode ->
Hyunsun Moon0d457362017-06-27 17:19:41 +0900258 setGatewayIcmpRule(
259 gatewayIp,
260 gNode.intgBridge(),
daniel park576969a2018-03-09 07:07:41 +0900261 install));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900262
263 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
264 log.debug(updateStr + "ICMP to {}", osSubnet.getGateway());
265 }
266
Jian Li4d138702018-11-27 17:25:28 +0900267 private void setGatewayIcmpForVxlan(Subnet osSubnet,
268 OpenstackNode srcNatGw,
269 Network network,
270 Set<Subnet> routableSubnets,
271 boolean install) {
272 osNodeService.completeNodes(COMPUTE).stream()
273 .filter(cNode -> cNode.dataIp() != null)
274 .forEach(cNode -> setRulesToGatewayWithRoutableSubnets(
275 cNode,
276 srcNatGw,
277 network.getProviderSegID(),
278 osSubnet,
279 routableSubnets,
Jian Li621f73c2018-12-15 01:49:22 +0900280 VXLAN,
Jian Li2d68c192018-12-13 15:52:59 +0900281 install));
282 }
283
284 private void setGatewayIcmpForGre(Subnet osSubnet,
285 OpenstackNode srcNatGw,
286 Network network,
287 Set<Subnet> routableSubnets,
288 boolean install) {
289 osNodeService.completeNodes(COMPUTE).stream()
290 .filter(cNode -> cNode.dataIp() != null)
291 .forEach(cNode -> setRulesToGatewayWithRoutableSubnets(
292 cNode,
293 srcNatGw,
294 network.getProviderSegID(),
295 osSubnet,
296 routableSubnets,
Jian Li621f73c2018-12-15 01:49:22 +0900297 GRE,
298 install));
299 }
300
301 private void setGatewayIcmpForGeneve(Subnet osSubnet,
302 OpenstackNode srcNatGw,
303 Network network,
304 Set<Subnet> routableSubnets,
305 boolean install) {
306 osNodeService.completeNodes(COMPUTE).stream()
307 .filter(cNode -> cNode.dataIp() != null)
308 .forEach(cNode -> setRulesToGatewayWithRoutableSubnets(
309 cNode,
310 srcNatGw,
311 network.getProviderSegID(),
312 osSubnet,
313 routableSubnets,
314 GENEVE,
Jian Li4d138702018-11-27 17:25:28 +0900315 install));
316 }
317
318 private void setGatewayIcmpForVlan(Subnet osSubnet,
319 OpenstackNode srcNatGw,
320 Network network,
321 Set<Subnet> routableSubnets,
322 boolean install) {
323 osNodeService.completeNodes(COMPUTE).stream()
324 .filter(cNode -> cNode.vlanPortNum() != null)
325 .forEach(cNode -> setRulesToGatewayWithRoutableSubnets(
326 cNode,
327 srcNatGw,
328 network.getProviderSegID(),
329 osSubnet,
330 routableSubnets,
SONA Project6bc5c4a2018-12-14 23:49:52 +0900331 VLAN,
Jian Li4d138702018-11-27 17:25:28 +0900332 install));
333 }
334
Hyunsun Moon44aac662017-02-18 02:07:01 +0900335 private void setInternalRoutes(Router osRouter, Subnet updatedSubnet, boolean install) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900336 Type netType = osNetworkAdminService.networkType(updatedSubnet.getNetworkId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900337 Set<Subnet> routableSubnets = routableSubnets(osRouter, updatedSubnet.getId());
Jian Lib6969502018-10-30 20:38:07 +0900338 String updatedSegmentId = getSegmentId(updatedSubnet);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900339
340 // installs rule from/to my subnet intentionally to fix ICMP failure
341 // to my subnet gateway if no external gateway added to the router
Hyunsun Moon0d457362017-06-27 17:19:41 +0900342 osNodeService.completeNodes(COMPUTE).forEach(cNode -> {
343 setInternalRouterRules(
344 cNode.intgBridge(),
Jian Lib6969502018-10-30 20:38:07 +0900345 updatedSegmentId,
346 updatedSegmentId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900347 IpPrefix.valueOf(updatedSubnet.getCidr()),
348 IpPrefix.valueOf(updatedSubnet.getCidr()),
SONA Project6bc5c4a2018-12-14 23:49:52 +0900349 netType,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900350 install
351 );
Hyunsun Moon44aac662017-02-18 02:07:01 +0900352
Hyunsun Moon0d457362017-06-27 17:19:41 +0900353 routableSubnets.forEach(subnet -> {
354 setInternalRouterRules(
355 cNode.intgBridge(),
Jian Lib6969502018-10-30 20:38:07 +0900356 updatedSegmentId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900357 getSegmentId(subnet),
358 IpPrefix.valueOf(updatedSubnet.getCidr()),
359 IpPrefix.valueOf(subnet.getCidr()),
SONA Project6bc5c4a2018-12-14 23:49:52 +0900360 netType,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900361 install
362 );
363 setInternalRouterRules(
364 cNode.intgBridge(),
365 getSegmentId(subnet),
Jian Lib6969502018-10-30 20:38:07 +0900366 updatedSegmentId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900367 IpPrefix.valueOf(subnet.getCidr()),
368 IpPrefix.valueOf(updatedSubnet.getCidr()),
SONA Project6bc5c4a2018-12-14 23:49:52 +0900369 netType,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900370 install
371 );
372 });
373 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900374
daniel parkee8700b2017-05-11 15:50:03 +0900375
Hyunsun Moon44aac662017-02-18 02:07:01 +0900376 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
377 routableSubnets.forEach(subnet -> log.debug(
378 updateStr + "route between subnet:{} and subnet:{}",
379 subnet.getCidr(),
380 updatedSubnet.getCidr()));
381 }
382
383 private Set<Subnet> routableSubnets(Router osRouter, String osSubnetId) {
384 Set<Subnet> osSubnets = osRouterService.routerInterfaces(osRouter.getId())
385 .stream()
386 .filter(iface -> !Objects.equals(iface.getSubnetId(), osSubnetId))
Jian Liedc8b762018-03-22 15:42:00 +0900387 .map(iface -> osNetworkAdminService.subnet(iface.getSubnetId()))
Hyunsun Moon44aac662017-02-18 02:07:01 +0900388 .collect(Collectors.toSet());
389 return ImmutableSet.copyOf(osSubnets);
390 }
391
daniel parkee8700b2017-05-11 15:50:03 +0900392 private String getSegmentId(Subnet osSubnet) {
Jian Liedc8b762018-03-22 15:42:00 +0900393 return osNetworkAdminService.network(osSubnet.getNetworkId()).getProviderSegID();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900394 }
395
396 private void setGatewayIcmpRule(IpAddress gatewayIp, DeviceId deviceId, boolean install) {
397 TrafficSelector selector = DefaultTrafficSelector.builder()
398 .matchEthType(Ethernet.TYPE_IPV4)
399 .matchIPProtocol(IPv4.PROTOCOL_ICMP)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900400 .matchIPDst(gatewayIp.getIp4Address().toIpPrefix())
Hyunsun Moon44aac662017-02-18 02:07:01 +0900401 .build();
402
403 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Li4d5c5c32018-04-02 16:38:18 +0900404 .punt()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900405 .build();
406
sanghodc375372017-06-08 10:41:30 +0900407 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900408 appId,
409 deviceId,
410 selector,
411 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900412 PRIORITY_ICMP_RULE,
sanghodc375372017-06-08 10:41:30 +0900413 Constants.GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900414 install);
415 }
416
Jian Li4d138702018-11-27 17:25:28 +0900417 private void setInternalRouterRules(DeviceId deviceId, String srcSegId, String dstSegId,
daniel parkee8700b2017-05-11 15:50:03 +0900418 IpPrefix srcSubnet, IpPrefix dstSubnet,
SONA Project6bc5c4a2018-12-14 23:49:52 +0900419 Type networkType, boolean install) {
Jian Li4d138702018-11-27 17:25:28 +0900420
daniel parkee8700b2017-05-11 15:50:03 +0900421 switch (networkType) {
422 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900423 case GRE:
Jian Li621f73c2018-12-15 01:49:22 +0900424 case GENEVE:
Jian Li2d68c192018-12-13 15:52:59 +0900425 setInternalRouterRulesForTunnel(deviceId, srcSegId, dstSegId,
Jian Li4d138702018-11-27 17:25:28 +0900426 srcSubnet, dstSubnet, install);
daniel parkee8700b2017-05-11 15:50:03 +0900427 break;
428 case VLAN:
Jian Li4d138702018-11-27 17:25:28 +0900429 setInternalRouterRulesForVlan(deviceId, srcSegId, dstSegId,
430 srcSubnet, dstSubnet, install);
daniel parkee8700b2017-05-11 15:50:03 +0900431 break;
432 default:
Jian Li4d138702018-11-27 17:25:28 +0900433 final String error = String.format("%s %s", ERR_UNSUPPORTED_NET_TYPE,
434 networkType.toString());
daniel parkee8700b2017-05-11 15:50:03 +0900435 throw new IllegalStateException(error);
436 }
437
Hyunsun Moon44aac662017-02-18 02:07:01 +0900438 }
439
Jian Li2d68c192018-12-13 15:52:59 +0900440 private void setInternalRouterRulesForTunnel(DeviceId deviceId,
441 String srcSegmentId,
442 String dstSegmentId,
443 IpPrefix srcSubnet,
444 IpPrefix dstSubnet,
445 boolean install) {
Jian Li4d138702018-11-27 17:25:28 +0900446 TrafficSelector selector;
447 TrafficTreatment treatment;
448 selector = DefaultTrafficSelector.builder()
449 .matchEthType(Ethernet.TYPE_IPV4)
450 .matchTunnelId(Long.parseLong(srcSegmentId))
451 .matchIPSrc(srcSubnet.getIp4Prefix())
452 .matchIPDst(dstSubnet.getIp4Prefix())
453 .build();
454
455 treatment = DefaultTrafficTreatment.builder()
456 .setTunnelId(Long.parseLong(dstSegmentId))
457 .transition(STAT_OUTBOUND_TABLE)
458 .build();
459
460 osFlowRuleService.setRule(
461 appId,
462 deviceId,
463 selector,
464 treatment,
465 PRIORITY_INTERNAL_ROUTING_RULE,
466 ROUTING_TABLE,
467 install);
468
469 selector = DefaultTrafficSelector.builder()
470 .matchEthType(Ethernet.TYPE_IPV4)
471 .matchTunnelId(Long.parseLong(dstSegmentId))
472 .matchIPSrc(srcSubnet.getIp4Prefix())
473 .matchIPDst(dstSubnet.getIp4Prefix())
474 .build();
475
476 treatment = DefaultTrafficTreatment.builder()
477 .setTunnelId(Long.parseLong(dstSegmentId))
478 .transition(STAT_OUTBOUND_TABLE)
479 .build();
480
481 osFlowRuleService.setRule(
482 appId,
483 deviceId,
484 selector,
485 treatment,
486 PRIORITY_INTERNAL_ROUTING_RULE,
487 ROUTING_TABLE,
488 install);
489 }
490
491 private void setInternalRouterRulesForVlan(DeviceId deviceId,
492 String srcSegmentId,
493 String dstSegmentId,
494 IpPrefix srcSubnet,
495 IpPrefix dstSubnet,
496 boolean install) {
497 TrafficSelector selector;
498 TrafficTreatment treatment;
499 selector = DefaultTrafficSelector.builder()
500 .matchEthType(Ethernet.TYPE_IPV4)
501 .matchVlanId(VlanId.vlanId(srcSegmentId))
502 .matchIPSrc(srcSubnet.getIp4Prefix())
503 .matchIPDst(dstSubnet.getIp4Prefix())
504 .build();
505
506 treatment = DefaultTrafficTreatment.builder()
507 .setVlanId(VlanId.vlanId(dstSegmentId))
508 .transition(STAT_OUTBOUND_TABLE)
509 .build();
510
511 osFlowRuleService.setRule(
512 appId,
513 deviceId,
514 selector,
515 treatment,
516 PRIORITY_INTERNAL_ROUTING_RULE,
517 ROUTING_TABLE,
518 install);
519
520 selector = DefaultTrafficSelector.builder()
521 .matchEthType(Ethernet.TYPE_IPV4)
522 .matchVlanId(VlanId.vlanId(dstSegmentId))
523 .matchIPSrc(srcSubnet.getIp4Prefix())
524 .matchIPDst(dstSubnet.getIp4Prefix())
525 .build();
526
527 treatment = DefaultTrafficTreatment.builder()
528 .setVlanId(VlanId.vlanId(dstSegmentId))
529 .transition(STAT_OUTBOUND_TABLE)
530 .build();
531
532 osFlowRuleService.setRule(
533 appId,
534 deviceId,
535 selector,
536 treatment,
537 PRIORITY_INTERNAL_ROUTING_RULE,
538 ROUTING_TABLE,
539 install);
540 }
541
Jian Li5ecfd1a2018-12-10 11:41:03 +0900542 private void setRulesToGatewayWithRoutableSubnets(OpenstackNode osNode,
543 OpenstackNode sourceNatGateway,
544 String segmentId,
545 Subnet updatedSubnet,
546 Set<Subnet> routableSubnets,
SONA Project6bc5c4a2018-12-14 23:49:52 +0900547 Type networkType,
Daniel Park51f9d1e2018-10-26 13:39:09 +0900548 boolean install) {
549 //At first we install flow rules to gateway with segId and gatewayIp of updated subnet
Jian Li5ecfd1a2018-12-10 11:41:03 +0900550 setRulesToGatewayWithDstIp(osNode, sourceNatGateway, segmentId,
Jian Li2d68c192018-12-13 15:52:59 +0900551 IpAddress.valueOf(updatedSubnet.getGateway()), networkType, install);
Daniel Park51f9d1e2018-10-26 13:39:09 +0900552
553 routableSubnets.forEach(subnet -> {
554 setRulesToGatewayWithDstIp(osNode, sourceNatGateway,
555 segmentId, IpAddress.valueOf(subnet.getGateway()),
Jian Li2d68c192018-12-13 15:52:59 +0900556 networkType, install);
Daniel Park51f9d1e2018-10-26 13:39:09 +0900557
558 Network network = osNetworkAdminService.network(subnet.getNetworkId());
559 setRulesToGatewayWithDstIp(osNode, sourceNatGateway,
560 network.getProviderSegID(), IpAddress.valueOf(updatedSubnet.getGateway()),
Jian Li2d68c192018-12-13 15:52:59 +0900561 networkType, install);
Daniel Park51f9d1e2018-10-26 13:39:09 +0900562 });
563 }
564
Jian Li5ecfd1a2018-12-10 11:41:03 +0900565 private void setRulesToGatewayWithDstIp(OpenstackNode osNode,
566 OpenstackNode sourceNatGateway,
567 String segmentId,
568 IpAddress dstIp,
SONA Project6bc5c4a2018-12-14 23:49:52 +0900569 Type networkType,
Jian Li5ecfd1a2018-12-10 11:41:03 +0900570 boolean install) {
Daniel Parkc64b4c62018-05-09 18:13:39 +0900571 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
572 .matchEthType(Ethernet.TYPE_IPV4)
573 .matchIPDst(dstIp.getIp4Address().toIpPrefix());
574
Daniel Parkc64b4c62018-05-09 18:13:39 +0900575 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
576
Jian Li2d68c192018-12-13 15:52:59 +0900577 switch (networkType) {
Daniel Parkc64b4c62018-05-09 18:13:39 +0900578 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900579 case GRE:
Jian Li621f73c2018-12-15 01:49:22 +0900580 case GENEVE:
Daniel Park51f9d1e2018-10-26 13:39:09 +0900581 sBuilder.matchTunnelId(Long.parseLong(segmentId));
Jian Li2d68c192018-12-13 15:52:59 +0900582
SONA Project6bc5c4a2018-12-14 23:49:52 +0900583 PortNumber portNum = tunnelPortNumByNetType(networkType, osNode);
Jian Li2d68c192018-12-13 15:52:59 +0900584
Daniel Parkc64b4c62018-05-09 18:13:39 +0900585 tBuilder.extension(buildExtension(
daniel parkb5817102018-02-15 00:18:51 +0900586 deviceService,
587 osNode.intgBridge(),
588 sourceNatGateway.dataIp().getIp4Address()),
589 osNode.intgBridge())
Jian Li2d68c192018-12-13 15:52:59 +0900590 .setOutput(portNum);
Daniel Parkc64b4c62018-05-09 18:13:39 +0900591 break;
Daniel Parkc64b4c62018-05-09 18:13:39 +0900592 case VLAN:
Daniel Park51f9d1e2018-10-26 13:39:09 +0900593 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
Daniel Parkc64b4c62018-05-09 18:13:39 +0900594 tBuilder.setOutput(osNode.vlanPortNum());
595 break;
596
597 default:
598 break;
599 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900600
sanghodc375372017-06-08 10:41:30 +0900601 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900602 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900603 osNode.intgBridge(),
Daniel Parkc64b4c62018-05-09 18:13:39 +0900604 sBuilder.build(),
605 tBuilder.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900606 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900607 ROUTING_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900608 install);
609 }
610
Jian Li5ecfd1a2018-12-10 11:41:03 +0900611 private void setRouterAdminRules(String segmentId,
SONA Project6bc5c4a2018-12-14 23:49:52 +0900612 Type networkType,
Jian Li5ecfd1a2018-12-10 11:41:03 +0900613 boolean install) {
Frank Wang245a6822017-06-14 09:51:35 +0800614 TrafficTreatment treatment;
615 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
616 .matchEthType(Ethernet.TYPE_IPV4);
617
618 switch (networkType) {
619 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900620 case GRE:
Jian Li621f73c2018-12-15 01:49:22 +0900621 case GENEVE:
Frank Wang245a6822017-06-14 09:51:35 +0800622 sBuilder.matchTunnelId(Long.parseLong(segmentId));
623 break;
624 case VLAN:
625 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
626 break;
627 default:
Jian Li71670d12018-03-02 21:31:07 +0900628 final String error = String.format("%s %s",
629 ERR_UNSUPPORTED_NET_TYPE,
Frank Wang245a6822017-06-14 09:51:35 +0800630 networkType.toString());
631 throw new IllegalStateException(error);
632 }
633
634 treatment = DefaultTrafficTreatment.builder()
635 .drop()
636 .build();
637
638 osNodeService.completeNodes().stream()
639 .filter(osNode -> osNode.type() == COMPUTE)
640 .forEach(osNode -> {
641 osFlowRuleService.setRule(
642 appId,
643 osNode.intgBridge(),
644 sBuilder.build(),
645 treatment,
646 PRIORITY_ADMIN_RULE,
647 ROUTING_TABLE,
648 install);
649 });
650 }
651
Hyunsun Moon44aac662017-02-18 02:07:01 +0900652 private class InternalRouterEventListener implements OpenstackRouterListener {
653
Jian Li34220ea2018-11-14 01:30:24 +0900654 private boolean isRelevantHelper() {
655 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900656 }
657
Hyunsun Moon44aac662017-02-18 02:07:01 +0900658 @Override
659 public void event(OpenstackRouterEvent event) {
660 switch (event.type()) {
661 case OPENSTACK_ROUTER_CREATED:
Jian Li4d138702018-11-27 17:25:28 +0900662 eventExecutor.execute(() -> processRouterCreation(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900663 break;
664 case OPENSTACK_ROUTER_UPDATED:
Jian Li4d138702018-11-27 17:25:28 +0900665 eventExecutor.execute(() -> processRouterUpdate(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900666 break;
667 case OPENSTACK_ROUTER_REMOVED:
Jian Li4d138702018-11-27 17:25:28 +0900668 eventExecutor.execute(() -> processRouterRemoval(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900669 break;
670 case OPENSTACK_ROUTER_INTERFACE_ADDED:
Jian Li4d138702018-11-27 17:25:28 +0900671 eventExecutor.execute(() -> processRouterIntfCreation(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900672 break;
673 case OPENSTACK_ROUTER_INTERFACE_UPDATED:
Jian Li4d138702018-11-27 17:25:28 +0900674 eventExecutor.execute(() -> processRouterIntfUpdate(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900675 break;
676 case OPENSTACK_ROUTER_INTERFACE_REMOVED:
Jian Li4d138702018-11-27 17:25:28 +0900677 eventExecutor.execute(() -> processRouterIntfRemoval(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900678 break;
679 case OPENSTACK_ROUTER_GATEWAY_ADDED:
Jian Li32b03622018-11-06 17:54:24 +0900680 log.debug("Router external gateway {} added",
681 event.externalGateway().getNetworkId());
Ray Milkey08932a72018-02-20 15:34:38 -0800682 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900683 case OPENSTACK_ROUTER_GATEWAY_REMOVED:
Jian Li32b03622018-11-06 17:54:24 +0900684 log.debug("Router external gateway {} removed",
685 event.externalGateway().getNetworkId());
Ray Milkey08932a72018-02-20 15:34:38 -0800686 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900687 case OPENSTACK_FLOATING_IP_CREATED:
688 case OPENSTACK_FLOATING_IP_UPDATED:
689 case OPENSTACK_FLOATING_IP_REMOVED:
690 case OPENSTACK_FLOATING_IP_ASSOCIATED:
691 case OPENSTACK_FLOATING_IP_DISASSOCIATED:
692 default:
693 // do nothing for the other events
694 break;
695 }
696 }
Jian Li4d138702018-11-27 17:25:28 +0900697
698 private void processRouterCreation(OpenstackRouterEvent event) {
699 if (!isRelevantHelper()) {
700 return;
701 }
702
703 log.debug("Router(name:{}, ID:{}) is created",
704 event.subject().getName(),
705 event.subject().getId());
706
707 routerUpdated(event.subject());
708 }
709
710 private void processRouterUpdate(OpenstackRouterEvent event) {
711 if (!isRelevantHelper()) {
712 return;
713 }
714
715 log.debug("Router(name:{}, ID:{}) is updated",
716 event.subject().getName(),
717 event.subject().getId());
718
719 routerUpdated(event.subject());
720 }
721
722 private void processRouterRemoval(OpenstackRouterEvent event) {
723 if (!isRelevantHelper()) {
724 return;
725 }
726
727 log.debug("Router(name:{}, ID:{}) is removed",
728 event.subject().getName(),
729 event.subject().getId());
730
731 routerRemove(event.subject());
732 }
733
734 private void processRouterIntfCreation(OpenstackRouterEvent event) {
735 if (!isRelevantHelper()) {
736 return;
737 }
738
739 log.debug("Router interface {} added to router {}",
740 event.routerIface().getPortId(),
741 event.routerIface().getId());
742
743 routerIfaceAdded(event.subject(), event.routerIface());
744 }
745
746 private void processRouterIntfUpdate(OpenstackRouterEvent event) {
747 log.debug("Router interface {} on {} updated",
748 event.routerIface().getPortId(),
749 event.routerIface().getId());
750 }
751
752 private void processRouterIntfRemoval(OpenstackRouterEvent event) {
753 if (!isRelevantHelper()) {
754 return;
755 }
756
757 log.debug("Router interface {} removed from router {}",
758 event.routerIface().getPortId(),
759 event.routerIface().getId());
760
761 routerIfaceRemoved(event.subject(), event.routerIface());
762 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900763 }
764
765 private class InternalNodeEventListener implements OpenstackNodeListener {
766
Jian Li34220ea2018-11-14 01:30:24 +0900767 private boolean isRelevantHelper() {
768 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900769 }
770
771 @Override
772 public void event(OpenstackNodeEvent event) {
773 OpenstackNode osNode = event.subject();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900774 switch (event.type()) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900775 case OPENSTACK_NODE_COMPLETE:
776 case OPENSTACK_NODE_INCOMPLETE:
Daniel Park6ed9cf02018-06-27 19:07:44 +0900777 case OPENSTACK_NODE_UPDATED:
778 case OPENSTACK_NODE_REMOVED:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900779 eventExecutor.execute(() -> {
Jian Li34220ea2018-11-14 01:30:24 +0900780 if (!isRelevantHelper()) {
781 return;
782 }
Jian Li4d138702018-11-27 17:25:28 +0900783 reconfigureRouters(osNode);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900784 });
785 break;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900786 case OPENSTACK_NODE_CREATED:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900787 default:
788 break;
789 }
790 }
791
Jian Li4d138702018-11-27 17:25:28 +0900792 private void reconfigureRouters(OpenstackNode osNode) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900793 osRouterService.routers().forEach(osRouter -> {
794 routerUpdated(osRouter);
795 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
796 routerIfaceAdded(osRouter, iface);
797 });
798 });
Jian Li4d138702018-11-27 17:25:28 +0900799 log.info("Reconfigure routers for {}", osNode.hostname());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900800 }
801 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900802}