blob: fafd6679a19dd02ab202cc03f24d693a58ac4f51 [file] [log] [blame]
Hyunsun Moon44aac662017-02-18 02:07:01 +09001/*
2 * Copyright 2016-present Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.openstacknetworking.impl;
17
18import com.google.common.base.Strings;
19import com.google.common.collect.ImmutableSet;
20import org.apache.felix.scr.annotations.Activate;
21import org.apache.felix.scr.annotations.Component;
22import org.apache.felix.scr.annotations.Deactivate;
23import org.apache.felix.scr.annotations.Reference;
24import org.apache.felix.scr.annotations.ReferenceCardinality;
25import org.onlab.packet.Ethernet;
26import org.onlab.packet.IPv4;
27import org.onlab.packet.IpAddress;
28import org.onlab.packet.IpPrefix;
sangho072c4dd2017-05-17 10:45:21 +090029import org.onlab.packet.MacAddress;
daniel parkee8700b2017-05-11 15:50:03 +090030import org.onlab.packet.VlanId;
Hyunsun Moon44aac662017-02-18 02:07:01 +090031import org.onosproject.cluster.ClusterService;
32import org.onosproject.cluster.LeadershipService;
33import org.onosproject.cluster.NodeId;
34import org.onosproject.core.ApplicationId;
35import org.onosproject.core.CoreService;
36import org.onosproject.core.GroupId;
sangho072c4dd2017-05-17 10:45:21 +090037import org.onosproject.mastership.MastershipService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090038import org.onosproject.net.DeviceId;
39import org.onosproject.net.PortNumber;
sangho072c4dd2017-05-17 10:45:21 +090040import org.onosproject.net.device.DeviceService;
41import org.onosproject.net.driver.DriverService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090042import org.onosproject.net.flow.DefaultTrafficSelector;
43import org.onosproject.net.flow.DefaultTrafficTreatment;
44import org.onosproject.net.flow.TrafficSelector;
45import org.onosproject.net.flow.TrafficTreatment;
sangho072c4dd2017-05-17 10:45:21 +090046import org.onosproject.net.flow.instructions.ExtensionTreatment;
Hyunsun Moon44aac662017-02-18 02:07:01 +090047import org.onosproject.openstacknetworking.api.Constants;
sangho072c4dd2017-05-17 10:45:21 +090048import org.onosproject.openstacknetworking.api.InstancePort;
49import org.onosproject.openstacknetworking.api.InstancePortEvent;
50import org.onosproject.openstacknetworking.api.InstancePortListener;
51import org.onosproject.openstacknetworking.api.InstancePortService;
sanghodc375372017-06-08 10:41:30 +090052import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090053import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
54import org.onosproject.openstacknetworking.api.OpenstackRouterEvent;
55import org.onosproject.openstacknetworking.api.OpenstackRouterListener;
56import org.onosproject.openstacknetworking.api.OpenstackRouterService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090057import org.onosproject.openstacknode.api.OpenstackNode;
58import org.onosproject.openstacknode.api.OpenstackNode.NetworkMode;
59import org.onosproject.openstacknode.api.OpenstackNodeEvent;
60import org.onosproject.openstacknode.api.OpenstackNodeListener;
61import org.onosproject.openstacknode.api.OpenstackNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090062import org.openstack4j.model.network.ExternalGateway;
63import org.openstack4j.model.network.Network;
daniel parkee8700b2017-05-11 15:50:03 +090064import org.openstack4j.model.network.NetworkType;
Hyunsun Moon44aac662017-02-18 02:07:01 +090065import org.openstack4j.model.network.Router;
66import org.openstack4j.model.network.RouterInterface;
67import org.openstack4j.model.network.Subnet;
68import org.slf4j.Logger;
69import org.slf4j.LoggerFactory;
70
71import java.util.Objects;
sangho072c4dd2017-05-17 10:45:21 +090072import java.util.Optional;
Hyunsun Moon44aac662017-02-18 02:07:01 +090073import java.util.Set;
74import java.util.concurrent.ExecutorService;
75import java.util.stream.Collectors;
76
77import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
78import static org.onlab.util.Tools.groupedThreads;
sangho072c4dd2017-05-17 10:45:21 +090079import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_EXTERNAL_ROUTER_MAC;
80import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_GATEWAY_MAC;
81import static org.onosproject.openstacknetworking.api.Constants.FORWARDING_TABLE;
82import static org.onosproject.openstacknetworking.api.Constants.GW_COMMON_TABLE;
83import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
84import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_EXTERNAL_ROUTING_RULE;
85import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ICMP_RULE;
86import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_INTERNAL_ROUTING_RULE;
87import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_OVS_SNAT_RULE;
88import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_SWITCHING_RULE;
89import static org.onosproject.openstacknetworking.api.Constants.ROUTING_TABLE;
90import static org.onosproject.openstacknetworking.impl.RulePopulatorUtil.buildExtension;
Hyunsun Moon0d457362017-06-27 17:19:41 +090091import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
92import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Hyunsun Moon44aac662017-02-18 02:07:01 +090093
94/**
95 * Handles OpenStack router events.
96 */
97@Component(immediate = true)
98public class OpenstackRoutingHandler {
99
100 private final Logger log = LoggerFactory.getLogger(getClass());
101
102 private static final String MSG_ENABLED = "Enabled ";
103 private static final String MSG_DISABLED = "Disabled ";
104 private static final String ERR_SET_FLOWS = "Failed to set flows for router %s:";
daniel parkee8700b2017-05-11 15:50:03 +0900105 private static final String ERR_UNSUPPORTED_NET_TYPE = "Unsupported network type";
Hyunsun Moon44aac662017-02-18 02:07:01 +0900106
107 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
108 protected CoreService coreService;
109
110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
111 protected LeadershipService leadershipService;
112
113 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
114 protected ClusterService clusterService;
115
116 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900117 protected OpenstackNodeService osNodeService;
118
119 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900120 protected OpenstackNetworkService osNetworkService;
121
122 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
123 protected OpenstackRouterService osRouterService;
124
daniel parkee8700b2017-05-11 15:50:03 +0900125 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho072c4dd2017-05-17 10:45:21 +0900126 protected InstancePortService instancePortService;
127
128 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
129 protected DeviceService deviceService;
130
131 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sanghodc375372017-06-08 10:41:30 +0900132 protected OpenstackFlowRuleService osFlowRuleService;
133
sangho072c4dd2017-05-17 10:45:21 +0900134 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
135 protected MastershipService mastershipService;
136
137 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
138 protected DriverService driverService;
139
Hyunsun Moon44aac662017-02-18 02:07:01 +0900140 private final ExecutorService eventExecutor = newSingleThreadScheduledExecutor(
141 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
142 private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
143 private final OpenstackRouterListener osRouterListener = new InternalRouterEventListener();
sangho072c4dd2017-05-17 10:45:21 +0900144 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900145
146 private ApplicationId appId;
147 private NodeId localNodeId;
148
149 @Activate
150 protected void activate() {
151 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
152 localNodeId = clusterService.getLocalNode().id();
153 leadershipService.runForLeadership(appId.name());
154 osNodeService.addListener(osNodeListener);
155 osRouterService.addListener(osRouterListener);
sangho072c4dd2017-05-17 10:45:21 +0900156 instancePortService.addListener(instancePortListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900157
158 log.info("Started");
159 }
160
161 @Deactivate
162 protected void deactivate() {
163 osRouterService.removeListener(osRouterListener);
164 osNodeService.removeListener(osNodeListener);
sangho072c4dd2017-05-17 10:45:21 +0900165 instancePortService.removeListener(instancePortListener);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900166 leadershipService.withdraw(appId.name());
167 eventExecutor.shutdown();
168
169 log.info("Stopped");
170 }
171
172 private void routerUpdated(Router osRouter) {
173 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
174 if (exGateway == null) {
175 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
sangho072c4dd2017-05-17 10:45:21 +0900176 setSourceNat(osRouter, iface, false);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900177 });
178 } else {
179 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
sangho072c4dd2017-05-17 10:45:21 +0900180 setSourceNat(osRouter, iface, exGateway.isEnableSnat());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900181 });
182 }
183 }
184
185 private void routerIfaceAdded(Router osRouter, RouterInterface osRouterIface) {
186 Subnet osSubnet = osNetworkService.subnet(osRouterIface.getSubnetId());
187 if (osSubnet == null) {
188 final String error = String.format(
189 ERR_SET_FLOWS + "subnet %s does not exist",
190 osRouterIface.getId(),
191 osRouterIface.getSubnetId());
192 throw new IllegalStateException(error);
193 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900194 setInternalRoutes(osRouter, osSubnet, true);
195 setGatewayIcmp(osSubnet, true);
196 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
197 if (exGateway != null && exGateway.isEnableSnat()) {
sangho072c4dd2017-05-17 10:45:21 +0900198 setSourceNat(osRouter, osRouterIface, true);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900199 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900200 log.info("Connected subnet({}) to {}", osSubnet.getCidr(), osRouter.getName());
201 }
202
203 private void routerIfaceRemoved(Router osRouter, RouterInterface osRouterIface) {
204 Subnet osSubnet = osNetworkService.subnet(osRouterIface.getSubnetId());
205 if (osSubnet == null) {
206 final String error = String.format(
207 ERR_SET_FLOWS + "subnet %s does not exist",
208 osRouterIface.getId(),
209 osRouterIface.getSubnetId());
210 throw new IllegalStateException(error);
211 }
212
213 setInternalRoutes(osRouter, osSubnet, false);
214 setGatewayIcmp(osSubnet, false);
215 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
216 if (exGateway != null && exGateway.isEnableSnat()) {
sangho072c4dd2017-05-17 10:45:21 +0900217 setSourceNat(osRouter, osRouterIface, false);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900218 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900219 log.info("Disconnected subnet({}) from {}", osSubnet.getCidr(), osRouter.getName());
220 }
221
sangho072c4dd2017-05-17 10:45:21 +0900222 private void setSourceNat(Router osRouter, RouterInterface routerIface, boolean install) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900223 Subnet osSubnet = osNetworkService.subnet(routerIface.getSubnetId());
224 Network osNet = osNetworkService.network(osSubnet.getNetworkId());
225
Hyunsun Moon0d457362017-06-27 17:19:41 +0900226 osNodeService.completeNodes(COMPUTE).forEach(cNode -> {
227 setRulesToGateway(cNode, osNet.getProviderSegID(),
228 IpPrefix.valueOf(osSubnet.getCidr()), osNet.getNetworkType(),
229 install);
230 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900231
sangho072c4dd2017-05-17 10:45:21 +0900232 IpAddress natAddress = getGatewayIpAddress(osRouter);
233 if (natAddress == null) {
234 return;
235 }
236 String netId = osNetworkService.subnet(routerIface.getSubnetId()).getNetworkId();
237
238 osNodeService.completeNodes(OpenstackNode.NodeType.GATEWAY)
239 .forEach(gwNode -> {
240 instancePortService.instancePorts(netId).stream()
241 .forEach(port -> setRulesForSnatIngressRule(gwNode.intgBridge(),
242 Long.parseLong(osNet.getProviderSegID()),
243 IpPrefix.valueOf(port.ipAddress(), 32),
244 port.deviceId(),
245 install));
246
247 setOvsNatIngressRule(gwNode.intgBridge(),
248 IpPrefix.valueOf(natAddress, 32),
249 Constants.DEFAULT_EXTERNAL_ROUTER_MAC, install);
250 setOvsNatEgressRule(gwNode.intgBridge(),
251 natAddress, Long.parseLong(osNet.getProviderSegID()),
252 gwNode.patchPortNum(), install);
253 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900254
255 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
256 log.info(updateStr + "external access for subnet({})", osSubnet.getCidr());
257 }
258
sangho072c4dd2017-05-17 10:45:21 +0900259 private IpAddress getGatewayIpAddress(Router osRouter) {
260
261 String extNetId = osNetworkService.network(osRouter.getExternalGatewayInfo().getNetworkId()).getId();
262 Optional<Subnet> extSubnet = osNetworkService.subnets().stream()
263 .filter(subnet -> subnet.getNetworkId().equals(extNetId))
264 .findAny();
265
266 if (!extSubnet.isPresent()) {
267 log.error("Cannot find externel subnet for the router");
268 return null;
269 }
270
271 return IpAddress.valueOf(extSubnet.get().getGateway());
272 }
273
Hyunsun Moon44aac662017-02-18 02:07:01 +0900274 private void setGatewayIcmp(Subnet osSubnet, boolean install) {
275 if (Strings.isNullOrEmpty(osSubnet.getGateway())) {
276 // do nothing if no gateway is set
277 return;
278 }
279
280 // take ICMP request to a subnet gateway through gateway node group
281 Network network = osNetworkService.network(osSubnet.getNetworkId());
daniel parkee8700b2017-05-11 15:50:03 +0900282 switch (network.getNetworkType()) {
283 case VXLAN:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900284 osNodeService.completeNodes(COMPUTE).stream()
285 .filter(cNode -> cNode.dataIp() != null)
286 .forEach(cNode -> setRulesToGatewayWithDstIp(
287 cNode,
288 cNode.gatewayGroupId(NetworkMode.VXLAN),
daniel parkee8700b2017-05-11 15:50:03 +0900289 network.getProviderSegID(),
290 IpAddress.valueOf(osSubnet.getGateway()),
291 NetworkMode.VXLAN,
292 install));
293 break;
294 case VLAN:
Hyunsun Moon0d457362017-06-27 17:19:41 +0900295 osNodeService.completeNodes(COMPUTE).stream()
296 .filter(cNode -> cNode.vlanPortNum() != null)
297 .forEach(cNode -> setRulesToGatewayWithDstIp(
298 cNode,
299 cNode.gatewayGroupId(NetworkMode.VLAN),
daniel parkee8700b2017-05-11 15:50:03 +0900300 network.getProviderSegID(),
301 IpAddress.valueOf(osSubnet.getGateway()),
302 NetworkMode.VLAN,
303 install));
304 break;
305 default:
306 final String error = String.format(
307 ERR_UNSUPPORTED_NET_TYPE + "%s",
308 network.getNetworkType().toString());
309 throw new IllegalStateException(error);
310 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900311
312 IpAddress gatewayIp = IpAddress.valueOf(osSubnet.getGateway());
Hyunsun Moon0d457362017-06-27 17:19:41 +0900313 osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
314 setGatewayIcmpRule(
315 gatewayIp,
316 gNode.intgBridge(),
317 install
318 );
319 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900320
321 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
322 log.debug(updateStr + "ICMP to {}", osSubnet.getGateway());
323 }
324
325 private void setInternalRoutes(Router osRouter, Subnet updatedSubnet, boolean install) {
daniel parkee8700b2017-05-11 15:50:03 +0900326 Network updatedNetwork = osNetworkService.network(updatedSubnet.getNetworkId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900327 Set<Subnet> routableSubnets = routableSubnets(osRouter, updatedSubnet.getId());
daniel parkee8700b2017-05-11 15:50:03 +0900328 String updatedSegmendId = getSegmentId(updatedSubnet);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900329
330 // installs rule from/to my subnet intentionally to fix ICMP failure
331 // to my subnet gateway if no external gateway added to the router
Hyunsun Moon0d457362017-06-27 17:19:41 +0900332 osNodeService.completeNodes(COMPUTE).forEach(cNode -> {
333 setInternalRouterRules(
334 cNode.intgBridge(),
335 updatedSegmendId,
336 updatedSegmendId,
337 IpPrefix.valueOf(updatedSubnet.getCidr()),
338 IpPrefix.valueOf(updatedSubnet.getCidr()),
339 updatedNetwork.getNetworkType(),
340 install
341 );
Hyunsun Moon44aac662017-02-18 02:07:01 +0900342
Hyunsun Moon0d457362017-06-27 17:19:41 +0900343 routableSubnets.forEach(subnet -> {
344 setInternalRouterRules(
345 cNode.intgBridge(),
346 updatedSegmendId,
347 getSegmentId(subnet),
348 IpPrefix.valueOf(updatedSubnet.getCidr()),
349 IpPrefix.valueOf(subnet.getCidr()),
350 updatedNetwork.getNetworkType(),
351 install
352 );
353 setInternalRouterRules(
354 cNode.intgBridge(),
355 getSegmentId(subnet),
356 updatedSegmendId,
357 IpPrefix.valueOf(subnet.getCidr()),
358 IpPrefix.valueOf(updatedSubnet.getCidr()),
359 updatedNetwork.getNetworkType(),
360 install
361 );
362 });
363 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900364
daniel parkee8700b2017-05-11 15:50:03 +0900365
Hyunsun Moon44aac662017-02-18 02:07:01 +0900366 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
367 routableSubnets.forEach(subnet -> log.debug(
368 updateStr + "route between subnet:{} and subnet:{}",
369 subnet.getCidr(),
370 updatedSubnet.getCidr()));
371 }
372
373 private Set<Subnet> routableSubnets(Router osRouter, String osSubnetId) {
374 Set<Subnet> osSubnets = osRouterService.routerInterfaces(osRouter.getId())
375 .stream()
376 .filter(iface -> !Objects.equals(iface.getSubnetId(), osSubnetId))
377 .map(iface -> osNetworkService.subnet(iface.getSubnetId()))
378 .collect(Collectors.toSet());
379 return ImmutableSet.copyOf(osSubnets);
380 }
381
daniel parkee8700b2017-05-11 15:50:03 +0900382 private String getSegmentId(Subnet osSubnet) {
383 return osNetworkService.network(osSubnet.getNetworkId()).getProviderSegID();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900384 }
385
386 private void setGatewayIcmpRule(IpAddress gatewayIp, DeviceId deviceId, boolean install) {
387 TrafficSelector selector = DefaultTrafficSelector.builder()
388 .matchEthType(Ethernet.TYPE_IPV4)
389 .matchIPProtocol(IPv4.PROTOCOL_ICMP)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900390 .matchIPDst(gatewayIp.getIp4Address().toIpPrefix())
Hyunsun Moon44aac662017-02-18 02:07:01 +0900391 .build();
392
393 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
394 .setOutput(PortNumber.CONTROLLER)
395 .build();
396
sanghodc375372017-06-08 10:41:30 +0900397 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900398 appId,
399 deviceId,
400 selector,
401 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900402 PRIORITY_ICMP_RULE,
sanghodc375372017-06-08 10:41:30 +0900403 Constants.GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900404 install);
405 }
406
daniel parkee8700b2017-05-11 15:50:03 +0900407 private void setInternalRouterRules(DeviceId deviceId, String srcSegmentId, String dstSegmentId,
408 IpPrefix srcSubnet, IpPrefix dstSubnet,
409 NetworkType networkType, boolean install) {
410 TrafficSelector selector;
411 TrafficTreatment treatment;
412 switch (networkType) {
413 case VXLAN:
414 selector = DefaultTrafficSelector.builder()
415 .matchEthType(Ethernet.TYPE_IPV4)
416 .matchTunnelId(Long.parseLong(srcSegmentId))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900417 .matchIPSrc(srcSubnet.getIp4Prefix())
418 .matchIPDst(dstSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900419 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900420
daniel parkee8700b2017-05-11 15:50:03 +0900421 treatment = DefaultTrafficTreatment.builder()
422 .setTunnelId(Long.parseLong(dstSegmentId))
sanghodc375372017-06-08 10:41:30 +0900423 .transition(FORWARDING_TABLE)
daniel parkee8700b2017-05-11 15:50:03 +0900424 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900425
sanghodc375372017-06-08 10:41:30 +0900426 osFlowRuleService.setRule(
daniel parkee8700b2017-05-11 15:50:03 +0900427 appId,
428 deviceId,
429 selector,
430 treatment,
daniel parkee8700b2017-05-11 15:50:03 +0900431 PRIORITY_INTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900432 ROUTING_TABLE,
daniel parkee8700b2017-05-11 15:50:03 +0900433 install);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900434
daniel parkee8700b2017-05-11 15:50:03 +0900435 selector = DefaultTrafficSelector.builder()
436 .matchEthType(Ethernet.TYPE_IPV4)
437 .matchTunnelId(Long.parseLong(dstSegmentId))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900438 .matchIPSrc(srcSubnet.getIp4Prefix())
439 .matchIPDst(dstSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900440 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900441
daniel parkee8700b2017-05-11 15:50:03 +0900442 treatment = DefaultTrafficTreatment.builder()
443 .setTunnelId(Long.parseLong(dstSegmentId))
sanghodc375372017-06-08 10:41:30 +0900444 .transition(FORWARDING_TABLE)
daniel parkee8700b2017-05-11 15:50:03 +0900445 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900446
sanghodc375372017-06-08 10:41:30 +0900447 osFlowRuleService.setRule(
daniel parkee8700b2017-05-11 15:50:03 +0900448 appId,
449 deviceId,
450 selector,
451 treatment,
daniel parkee8700b2017-05-11 15:50:03 +0900452 PRIORITY_INTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900453 ROUTING_TABLE,
daniel parkee8700b2017-05-11 15:50:03 +0900454 install);
455 break;
456 case VLAN:
457 selector = DefaultTrafficSelector.builder()
458 .matchEthType(Ethernet.TYPE_IPV4)
459 .matchVlanId(VlanId.vlanId(srcSegmentId))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900460 .matchIPSrc(srcSubnet.getIp4Prefix())
461 .matchIPDst(dstSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900462 .build();
463
464 treatment = DefaultTrafficTreatment.builder()
465 .setVlanId(VlanId.vlanId(dstSegmentId))
sanghodc375372017-06-08 10:41:30 +0900466 .transition(FORWARDING_TABLE)
daniel parkee8700b2017-05-11 15:50:03 +0900467 .build();
468
sanghodc375372017-06-08 10:41:30 +0900469 osFlowRuleService.setRule(
daniel parkee8700b2017-05-11 15:50:03 +0900470 appId,
471 deviceId,
472 selector,
473 treatment,
daniel parkee8700b2017-05-11 15:50:03 +0900474 PRIORITY_INTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900475 ROUTING_TABLE,
daniel parkee8700b2017-05-11 15:50:03 +0900476 install);
477
478 selector = DefaultTrafficSelector.builder()
479 .matchEthType(Ethernet.TYPE_IPV4)
480 .matchVlanId(VlanId.vlanId(dstSegmentId))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900481 .matchIPSrc(srcSubnet.getIp4Prefix())
482 .matchIPDst(dstSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900483 .build();
484
485 treatment = DefaultTrafficTreatment.builder()
486 .setVlanId(VlanId.vlanId(dstSegmentId))
sanghodc375372017-06-08 10:41:30 +0900487 .transition(FORWARDING_TABLE)
daniel parkee8700b2017-05-11 15:50:03 +0900488 .build();
489
sanghodc375372017-06-08 10:41:30 +0900490 osFlowRuleService.setRule(
daniel parkee8700b2017-05-11 15:50:03 +0900491 appId,
492 deviceId,
493 selector,
494 treatment,
daniel parkee8700b2017-05-11 15:50:03 +0900495 PRIORITY_INTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900496 ROUTING_TABLE,
daniel parkee8700b2017-05-11 15:50:03 +0900497 install);
498 break;
499 default:
500 final String error = String.format(
501 ERR_UNSUPPORTED_NET_TYPE + "%s",
502 networkType.toString());
503 throw new IllegalStateException(error);
504 }
505
Hyunsun Moon44aac662017-02-18 02:07:01 +0900506 }
507
Hyunsun Moon0d457362017-06-27 17:19:41 +0900508 private void setRulesToGateway(OpenstackNode osNode, String segmentId, IpPrefix srcSubnet,
daniel parkee8700b2017-05-11 15:50:03 +0900509 NetworkType networkType, boolean install) {
510 TrafficTreatment treatment;
511 GroupId groupId;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900512
daniel parkee8700b2017-05-11 15:50:03 +0900513 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
514 .matchEthType(Ethernet.TYPE_IPV4)
Hyunsun Moon0d457362017-06-27 17:19:41 +0900515 .matchIPSrc(srcSubnet.getIp4Prefix())
daniel parkee8700b2017-05-11 15:50:03 +0900516 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
517
518 switch (networkType) {
519 case VXLAN:
520 sBuilder.matchTunnelId(Long.parseLong(segmentId));
Hyunsun Moon0d457362017-06-27 17:19:41 +0900521 groupId = osNode.gatewayGroupId(NetworkMode.VXLAN);
daniel parkee8700b2017-05-11 15:50:03 +0900522 break;
523 case VLAN:
524 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
Hyunsun Moon0d457362017-06-27 17:19:41 +0900525 groupId = osNode.gatewayGroupId(NetworkMode.VLAN);
daniel parkee8700b2017-05-11 15:50:03 +0900526 break;
527 default:
528 final String error = String.format(
529 ERR_UNSUPPORTED_NET_TYPE + "%s",
530 networkType.toString());
531 throw new IllegalStateException(error);
532 }
533
534 treatment = DefaultTrafficTreatment.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900535 .group(groupId)
536 .build();
537
sanghodc375372017-06-08 10:41:30 +0900538 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900539 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900540 osNode.intgBridge(),
daniel parkee8700b2017-05-11 15:50:03 +0900541 sBuilder.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900542 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900543 PRIORITY_EXTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900544 ROUTING_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900545 install);
546 }
547
sangho072c4dd2017-05-17 10:45:21 +0900548 private void setRulesForSnatIngressRule(DeviceId deviceId, Long vni, IpPrefix destVmIp,
549 DeviceId dstDeviceId, boolean install) {
550
551 TrafficSelector selector = DefaultTrafficSelector.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900552 .matchEthType(Ethernet.TYPE_IPV4)
sangho072c4dd2017-05-17 10:45:21 +0900553 .matchIPDst(destVmIp)
554 .build();
Hyunsun Moon0d457362017-06-27 17:19:41 +0900555
sangho072c4dd2017-05-17 10:45:21 +0900556 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
557 .setTunnelId(vni)
558 .extension(buildExtension(
559 deviceService,
560 deviceId,
561 osNodeService.node(dstDeviceId).dataIp().getIp4Address()),
562 deviceId)
563 .setOutput(osNodeService.node(deviceId).tunnelPortNum())
564 .build();
daniel parkee8700b2017-05-11 15:50:03 +0900565
sanghodc375372017-06-08 10:41:30 +0900566 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900567 appId,
sangho072c4dd2017-05-17 10:45:21 +0900568 deviceId,
569 selector,
570 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900571 PRIORITY_EXTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900572 Constants.GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900573 install);
574 }
575
Hyunsun Moon0d457362017-06-27 17:19:41 +0900576 private void setRulesToGatewayWithDstIp(OpenstackNode osNode, GroupId groupId,
577 String segmentId, IpAddress dstIp,
578 NetworkMode networkMode, boolean install) {
daniel parkee8700b2017-05-11 15:50:03 +0900579 TrafficSelector selector;
580 if (networkMode.equals(NetworkMode.VXLAN)) {
581 selector = DefaultTrafficSelector.builder()
582 .matchEthType(Ethernet.TYPE_IPV4)
583 .matchTunnelId(Long.valueOf(segmentId))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900584 .matchIPDst(dstIp.getIp4Address().toIpPrefix())
daniel parkee8700b2017-05-11 15:50:03 +0900585 .build();
586 } else {
587 selector = DefaultTrafficSelector.builder()
588 .matchEthType(Ethernet.TYPE_IPV4)
589 .matchVlanId(VlanId.vlanId(segmentId))
Hyunsun Moon0d457362017-06-27 17:19:41 +0900590 .matchIPDst(dstIp.getIp4Address().toIpPrefix())
daniel parkee8700b2017-05-11 15:50:03 +0900591 .build();
592 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900593
594 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
595 .group(groupId)
596 .build();
597
sanghodc375372017-06-08 10:41:30 +0900598 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900599 appId,
Hyunsun Moon0d457362017-06-27 17:19:41 +0900600 osNode.intgBridge(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900601 selector,
602 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900603 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900604 ROUTING_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900605 install);
606 }
607
sangho072c4dd2017-05-17 10:45:21 +0900608 private void setOvsNatIngressRule(DeviceId deviceId, IpPrefix cidr, MacAddress dstMac, boolean install) {
609
610 TrafficSelector selector = DefaultTrafficSelector.builder()
611 .matchEthType(Ethernet.TYPE_IPV4)
612 .matchIPDst(cidr)
613 .build();
614
615 ExtensionTreatment natTreatment = RulePopulatorUtil.niciraConnTrackTreatmentBuilder(driverService, deviceId)
616 .commit(false)
617 .natAction(true)
618 .table((short) 0)
619 .build();
620
621 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
622 .setEthDst(dstMac)
623 .extension(natTreatment, deviceId)
624 .build();
625
626 osFlowRuleService.setRule(
627 appId,
628 deviceId,
629 selector,
630 treatment,
631 PRIORITY_OVS_SNAT_RULE,
632 GW_COMMON_TABLE,
633 install);
634 }
635
636 private void setOvsNatEgressRule(DeviceId deviceId, IpAddress natAddress, long vni, PortNumber output,
637 boolean install) {
638
639 TrafficSelector selector = DefaultTrafficSelector.builder()
640 .matchEthType(Ethernet.TYPE_IPV4)
641 .matchEthDst(DEFAULT_GATEWAY_MAC)
642 .matchTunnelId(vni)
643 .build();
644
645 ExtensionTreatment natTreatment = RulePopulatorUtil.niciraConnTrackTreatmentBuilder(driverService, deviceId)
646 .commit(true)
647 .natAction(true)
648 .natIp(natAddress)
649 .build();
650
651 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
652 .extension(natTreatment, deviceId)
653 .setEthDst(DEFAULT_EXTERNAL_ROUTER_MAC)
654 .setEthSrc(DEFAULT_GATEWAY_MAC)
655 .setOutput(output)
656 .build();
657
658 osFlowRuleService.setRule(
659 appId,
660 deviceId,
661 selector,
662 treatment,
663 PRIORITY_OVS_SNAT_RULE,
664 GW_COMMON_TABLE,
665 install);
666 }
667
668
Hyunsun Moon44aac662017-02-18 02:07:01 +0900669 private class InternalRouterEventListener implements OpenstackRouterListener {
670
671 @Override
672 public boolean isRelevant(OpenstackRouterEvent event) {
673 // do not allow to proceed without leadership
674 NodeId leader = leadershipService.getLeader(appId.name());
675 return Objects.equals(localNodeId, leader);
676 }
677
678 // FIXME only one leader in the cluster should process
679 @Override
680 public void event(OpenstackRouterEvent event) {
681 switch (event.type()) {
682 case OPENSTACK_ROUTER_CREATED:
683 log.debug("Router(name:{}, ID:{}) is created",
684 event.subject().getName(),
685 event.subject().getId());
686 eventExecutor.execute(() -> routerUpdated(event.subject()));
687 break;
688 case OPENSTACK_ROUTER_UPDATED:
689 log.debug("Router(name:{}, ID:{}) is updated",
690 event.subject().getName(),
691 event.subject().getId());
692 eventExecutor.execute(() -> routerUpdated(event.subject()));
693 break;
694 case OPENSTACK_ROUTER_REMOVED:
695 log.debug("Router(name:{}, ID:{}) is removed",
696 event.subject().getName(),
697 event.subject().getId());
698 break;
699 case OPENSTACK_ROUTER_INTERFACE_ADDED:
700 log.debug("Router interface {} added to router {}",
701 event.routerIface().getPortId(),
702 event.routerIface().getId());
703 eventExecutor.execute(() -> routerIfaceAdded(
704 event.subject(),
705 event.routerIface()));
706 break;
707 case OPENSTACK_ROUTER_INTERFACE_UPDATED:
708 log.debug("Router interface {} on {} updated",
709 event.routerIface().getPortId(),
710 event.routerIface().getId());
711 break;
712 case OPENSTACK_ROUTER_INTERFACE_REMOVED:
713 log.debug("Router interface {} removed from router {}",
714 event.routerIface().getPortId(),
715 event.routerIface().getId());
716 eventExecutor.execute(() -> routerIfaceRemoved(
717 event.subject(),
718 event.routerIface()));
719 break;
720 case OPENSTACK_ROUTER_GATEWAY_ADDED:
721 case OPENSTACK_ROUTER_GATEWAY_REMOVED:
722 case OPENSTACK_FLOATING_IP_CREATED:
723 case OPENSTACK_FLOATING_IP_UPDATED:
724 case OPENSTACK_FLOATING_IP_REMOVED:
725 case OPENSTACK_FLOATING_IP_ASSOCIATED:
726 case OPENSTACK_FLOATING_IP_DISASSOCIATED:
727 default:
728 // do nothing for the other events
729 break;
730 }
731 }
732 }
733
734 private class InternalNodeEventListener implements OpenstackNodeListener {
735
736 @Override
737 public boolean isRelevant(OpenstackNodeEvent event) {
738 // do not allow to proceed without leadership
739 NodeId leader = leadershipService.getLeader(appId.name());
740 return Objects.equals(localNodeId, leader);
741 }
742
743 @Override
744 public void event(OpenstackNodeEvent event) {
745 OpenstackNode osNode = event.subject();
746
747 switch (event.type()) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900748 case OPENSTACK_NODE_COMPLETE:
749 case OPENSTACK_NODE_INCOMPLETE:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900750 eventExecutor.execute(() -> {
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900751 log.info("Reconfigure routers for {}", osNode.hostname());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900752 reconfigureRouters();
753 });
754 break;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900755 case OPENSTACK_NODE_CREATED:
756 case OPENSTACK_NODE_UPDATED:
757 case OPENSTACK_NODE_REMOVED:
Hyunsun Moon44aac662017-02-18 02:07:01 +0900758 default:
759 break;
760 }
761 }
762
763 private void reconfigureRouters() {
764 osRouterService.routers().forEach(osRouter -> {
765 routerUpdated(osRouter);
766 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
767 routerIfaceAdded(osRouter, iface);
768 });
769 });
770 }
771 }
sangho072c4dd2017-05-17 10:45:21 +0900772
773 private class InternalInstancePortListener implements InstancePortListener {
774
775 @Override
776 public boolean isRelevant(InstancePortEvent event) {
777 InstancePort instPort = event.subject();
778 return mastershipService.isLocalMaster(instPort.deviceId());
779 }
780
781 @Override
782 public void event(InstancePortEvent event) {
783 InstancePort instPort = event.subject();
784 switch (event.type()) {
785 case OPENSTACK_INSTANCE_PORT_UPDATED:
786 case OPENSTACK_INSTANCE_PORT_DETECTED:
787 eventExecutor.execute(() -> {
788 log.info("RoutingHandler: Instance port detected MAC:{} IP:{}",
789 instPort.macAddress(),
790 instPort.ipAddress());
791 instPortDetected(event.subject());
792 });
793 break;
794 case OPENSTACK_INSTANCE_PORT_VANISHED:
795 eventExecutor.execute(() -> {
796 log.info("RoutingHandler: Instance port vanished MAC:{} IP:{}",
797 instPort.macAddress(),
798 instPort.ipAddress());
799 instPortRemoved(event.subject());
800 });
801 break;
802 default:
803 break;
804 }
805 }
806
807 private void instPortDetected(InstancePort instPort) {
808 osNodeService.completeNodes(GATEWAY)
809 .forEach(gwNode -> setRulesForSnatIngressRule(gwNode.intgBridge(),
810 Long.parseLong(osNetworkService.network(instPort.networkId()).getProviderSegID()),
811 IpPrefix.valueOf(instPort.ipAddress(), 32),
812 instPort.deviceId(),
813 true));
814 }
815
816 private void instPortRemoved(InstancePort instPort) {
817 osNodeService.completeNodes(GATEWAY)
818 .forEach(gwNode -> setRulesForSnatIngressRule(gwNode.intgBridge(),
819 Long.parseLong(osNetworkService.network(instPort.networkId()).getProviderSegID()),
820 IpPrefix.valueOf(instPort.ipAddress(), 32),
821 instPort.deviceId(),
822 false));
823 }
824 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900825}