blob: e0b5ccb3c7d024a3b4590acb68ef529f1d411ddb [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;
daniel parkee8700b2017-05-11 15:50:03 +090029import org.onlab.packet.MacAddress;
30import 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;
37import org.onosproject.net.DeviceId;
38import org.onosproject.net.PortNumber;
daniel parkee8700b2017-05-11 15:50:03 +090039import org.onosproject.net.device.DeviceService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090040import org.onosproject.net.flow.DefaultTrafficSelector;
41import org.onosproject.net.flow.DefaultTrafficTreatment;
42import org.onosproject.net.flow.TrafficSelector;
43import org.onosproject.net.flow.TrafficTreatment;
Hyunsun Moon44aac662017-02-18 02:07:01 +090044import org.onosproject.openstacknetworking.api.Constants;
sanghodc375372017-06-08 10:41:30 +090045import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090046import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
47import org.onosproject.openstacknetworking.api.OpenstackRouterEvent;
48import org.onosproject.openstacknetworking.api.OpenstackRouterListener;
49import org.onosproject.openstacknetworking.api.OpenstackRouterService;
50import org.onosproject.openstacknode.OpenstackNode;
51import org.onosproject.openstacknode.OpenstackNodeEvent;
52import org.onosproject.openstacknode.OpenstackNodeListener;
53import org.onosproject.openstacknode.OpenstackNodeService;
daniel parkee8700b2017-05-11 15:50:03 +090054import org.onosproject.openstacknode.OpenstackNodeService.NetworkMode;
Hyunsun Moon44aac662017-02-18 02:07:01 +090055import org.openstack4j.model.network.ExternalGateway;
56import org.openstack4j.model.network.Network;
daniel parkee8700b2017-05-11 15:50:03 +090057import org.openstack4j.model.network.NetworkType;
Hyunsun Moon44aac662017-02-18 02:07:01 +090058import org.openstack4j.model.network.Router;
59import org.openstack4j.model.network.RouterInterface;
60import org.openstack4j.model.network.Subnet;
61import 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;
daniel parkee8700b2017-05-11 15:50:03 +090071import static org.onosproject.net.AnnotationKeys.PORT_MAC;
72import static org.onosproject.net.AnnotationKeys.PORT_NAME;
sanghodc375372017-06-08 10:41:30 +090073import static org.onosproject.openstacknetworking.api.Constants.FORWARDING_TABLE;
74import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
75import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_EXTERNAL_ROUTING_RULE;
76import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ICMP_RULE;
77import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_INTERNAL_ROUTING_RULE;
78import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_SWITCHING_RULE;
79import static org.onosproject.openstacknetworking.api.Constants.ROUTING_TABLE;
Hyunsun Moon44aac662017-02-18 02:07:01 +090080import static org.onosproject.openstacknode.OpenstackNodeService.NodeType.COMPUTE;
81
82/**
83 * Handles OpenStack router events.
84 */
85@Component(immediate = true)
86public class OpenstackRoutingHandler {
87
88 private final Logger log = LoggerFactory.getLogger(getClass());
89
90 private static final String MSG_ENABLED = "Enabled ";
91 private static final String MSG_DISABLED = "Disabled ";
92 private static final String ERR_SET_FLOWS = "Failed to set flows for router %s:";
daniel parkee8700b2017-05-11 15:50:03 +090093 private static final String ERR_UNSUPPORTED_NET_TYPE = "Unsupported network type";
Hyunsun Moon44aac662017-02-18 02:07:01 +090094
95 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
96 protected CoreService coreService;
97
98 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
99 protected LeadershipService leadershipService;
100
101 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
102 protected ClusterService clusterService;
103
104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900105 protected OpenstackNodeService osNodeService;
106
107 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900108 protected OpenstackNetworkService osNetworkService;
109
110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
111 protected OpenstackRouterService osRouterService;
112
daniel parkee8700b2017-05-11 15:50:03 +0900113 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
114 protected DeviceService deviceService;
115
sanghodc375372017-06-08 10:41:30 +0900116 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
117 protected OpenstackFlowRuleService osFlowRuleService;
118
Hyunsun Moon44aac662017-02-18 02:07:01 +0900119 private final ExecutorService eventExecutor = newSingleThreadScheduledExecutor(
120 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
121 private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
122 private final OpenstackRouterListener osRouterListener = new InternalRouterEventListener();
123
124 private ApplicationId appId;
125 private NodeId localNodeId;
126
127 @Activate
128 protected void activate() {
129 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
130 localNodeId = clusterService.getLocalNode().id();
131 leadershipService.runForLeadership(appId.name());
132 osNodeService.addListener(osNodeListener);
133 osRouterService.addListener(osRouterListener);
134
135 log.info("Started");
136 }
137
138 @Deactivate
139 protected void deactivate() {
140 osRouterService.removeListener(osRouterListener);
141 osNodeService.removeListener(osNodeListener);
142 leadershipService.withdraw(appId.name());
143 eventExecutor.shutdown();
144
145 log.info("Stopped");
146 }
147
148 private void routerUpdated(Router osRouter) {
149 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
150 if (exGateway == null) {
151 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
152 setSourceNat(iface, false);
153 });
154 } else {
155 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
156 setSourceNat(iface, exGateway.isEnableSnat());
157 });
158 }
159 }
160
161 private void routerIfaceAdded(Router osRouter, RouterInterface osRouterIface) {
162 Subnet osSubnet = osNetworkService.subnet(osRouterIface.getSubnetId());
163 if (osSubnet == null) {
164 final String error = String.format(
165 ERR_SET_FLOWS + "subnet %s does not exist",
166 osRouterIface.getId(),
167 osRouterIface.getSubnetId());
168 throw new IllegalStateException(error);
169 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900170 setInternalRoutes(osRouter, osSubnet, true);
171 setGatewayIcmp(osSubnet, true);
172 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
173 if (exGateway != null && exGateway.isEnableSnat()) {
174 setSourceNat(osRouterIface, true);
175 }
176
177 log.info("Connected subnet({}) to {}", osSubnet.getCidr(), osRouter.getName());
178 }
179
180 private void routerIfaceRemoved(Router osRouter, RouterInterface osRouterIface) {
181 Subnet osSubnet = osNetworkService.subnet(osRouterIface.getSubnetId());
182 if (osSubnet == null) {
183 final String error = String.format(
184 ERR_SET_FLOWS + "subnet %s does not exist",
185 osRouterIface.getId(),
186 osRouterIface.getSubnetId());
187 throw new IllegalStateException(error);
188 }
189
190 setInternalRoutes(osRouter, osSubnet, false);
191 setGatewayIcmp(osSubnet, false);
192 ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
193 if (exGateway != null && exGateway.isEnableSnat()) {
194 setSourceNat(osRouterIface, false);
195 }
196
197 log.info("Disconnected subnet({}) from {}", osSubnet.getCidr(), osRouter.getName());
198 }
199
200 private void setSourceNat(RouterInterface routerIface, boolean install) {
201 Subnet osSubnet = osNetworkService.subnet(routerIface.getSubnetId());
202 Network osNet = osNetworkService.network(osSubnet.getNetworkId());
203
204 osNodeService.completeNodes().stream()
205 .filter(osNode -> osNode.type() == COMPUTE)
206 .forEach(osNode -> {
daniel parkee8700b2017-05-11 15:50:03 +0900207 setRulesToGateway(osNode.intBridge(), osNet.getProviderSegID(),
208 IpPrefix.valueOf(osSubnet.getCidr()), osNet.getNetworkType(),
209 install);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900210 });
211
212 // take the first outgoing packet to controller for source NAT
daniel parke49eb382017-04-05 16:48:28 +0900213 osNodeService.gatewayDeviceIds()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900214 .forEach(gwDeviceId -> setRulesToController(
215 gwDeviceId,
daniel parkee8700b2017-05-11 15:50:03 +0900216 osNet.getProviderSegID(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900217 IpPrefix.valueOf(osSubnet.getCidr()),
daniel parkee8700b2017-05-11 15:50:03 +0900218 osNet.getNetworkType(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900219 install));
220
221 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
222 log.info(updateStr + "external access for subnet({})", osSubnet.getCidr());
223 }
224
225 private void setGatewayIcmp(Subnet osSubnet, boolean install) {
226 if (Strings.isNullOrEmpty(osSubnet.getGateway())) {
227 // do nothing if no gateway is set
228 return;
229 }
230
231 // take ICMP request to a subnet gateway through gateway node group
232 Network network = osNetworkService.network(osSubnet.getNetworkId());
daniel parkee8700b2017-05-11 15:50:03 +0900233 switch (network.getNetworkType()) {
234 case VXLAN:
235 osNodeService.completeNodes().stream()
236 .filter(osNode -> osNode.type() == COMPUTE)
237 .filter(osNode -> osNode.dataIp().isPresent())
238 .forEach(osNode -> setRulesToGatewayWithDstIp(
239 osNode.intBridge(),
240 osNodeService.gatewayGroupId(osNode.intBridge(), NetworkMode.VXLAN),
241 network.getProviderSegID(),
242 IpAddress.valueOf(osSubnet.getGateway()),
243 NetworkMode.VXLAN,
244 install));
245 break;
246 case VLAN:
247 osNodeService.completeNodes().stream()
248 .filter(osNode -> osNode.type() == COMPUTE)
249 .filter(osNode -> osNode.vlanPort().isPresent())
250 .forEach(osNode -> setRulesToGatewayWithDstIp(
251 osNode.intBridge(),
252 osNodeService.gatewayGroupId(osNode.intBridge(), NetworkMode.VLAN),
253 network.getProviderSegID(),
254 IpAddress.valueOf(osSubnet.getGateway()),
255 NetworkMode.VLAN,
256 install));
257 break;
258 default:
259 final String error = String.format(
260 ERR_UNSUPPORTED_NET_TYPE + "%s",
261 network.getNetworkType().toString());
262 throw new IllegalStateException(error);
263 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900264
265 IpAddress gatewayIp = IpAddress.valueOf(osSubnet.getGateway());
daniel parke49eb382017-04-05 16:48:28 +0900266 osNodeService.gatewayDeviceIds()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900267 .forEach(gwDeviceId -> setGatewayIcmpRule(
268 gatewayIp,
269 gwDeviceId,
270 install
271 ));
272
273 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
274 log.debug(updateStr + "ICMP to {}", osSubnet.getGateway());
275 }
276
277 private void setInternalRoutes(Router osRouter, Subnet updatedSubnet, boolean install) {
daniel parkee8700b2017-05-11 15:50:03 +0900278 Network updatedNetwork = osNetworkService.network(updatedSubnet.getNetworkId());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900279 Set<Subnet> routableSubnets = routableSubnets(osRouter, updatedSubnet.getId());
daniel parkee8700b2017-05-11 15:50:03 +0900280 String updatedSegmendId = getSegmentId(updatedSubnet);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900281
282 // installs rule from/to my subnet intentionally to fix ICMP failure
283 // to my subnet gateway if no external gateway added to the router
284 osNodeService.completeNodes().stream()
285 .filter(osNode -> osNode.type() == COMPUTE)
286 .forEach(osNode -> {
287 setInternalRouterRules(
288 osNode.intBridge(),
daniel parkee8700b2017-05-11 15:50:03 +0900289 updatedSegmendId,
290 updatedSegmendId,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900291 IpPrefix.valueOf(updatedSubnet.getCidr()),
292 IpPrefix.valueOf(updatedSubnet.getCidr()),
daniel parkee8700b2017-05-11 15:50:03 +0900293 updatedNetwork.getNetworkType(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900294 install
295 );
296
297 routableSubnets.forEach(subnet -> {
298 setInternalRouterRules(
299 osNode.intBridge(),
daniel parkee8700b2017-05-11 15:50:03 +0900300 updatedSegmendId,
301 getSegmentId(subnet),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900302 IpPrefix.valueOf(updatedSubnet.getCidr()),
303 IpPrefix.valueOf(subnet.getCidr()),
daniel parkee8700b2017-05-11 15:50:03 +0900304 updatedNetwork.getNetworkType(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900305 install
306 );
307 setInternalRouterRules(
308 osNode.intBridge(),
daniel parkee8700b2017-05-11 15:50:03 +0900309 getSegmentId(subnet),
310 updatedSegmendId,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900311 IpPrefix.valueOf(subnet.getCidr()),
312 IpPrefix.valueOf(updatedSubnet.getCidr()),
daniel parkee8700b2017-05-11 15:50:03 +0900313 updatedNetwork.getNetworkType(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900314 install
315 );
316 });
317 });
318
daniel parkee8700b2017-05-11 15:50:03 +0900319
Hyunsun Moon44aac662017-02-18 02:07:01 +0900320 final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
321 routableSubnets.forEach(subnet -> log.debug(
322 updateStr + "route between subnet:{} and subnet:{}",
323 subnet.getCidr(),
324 updatedSubnet.getCidr()));
325 }
326
327 private Set<Subnet> routableSubnets(Router osRouter, String osSubnetId) {
328 Set<Subnet> osSubnets = osRouterService.routerInterfaces(osRouter.getId())
329 .stream()
330 .filter(iface -> !Objects.equals(iface.getSubnetId(), osSubnetId))
331 .map(iface -> osNetworkService.subnet(iface.getSubnetId()))
332 .collect(Collectors.toSet());
333 return ImmutableSet.copyOf(osSubnets);
334 }
335
daniel parkee8700b2017-05-11 15:50:03 +0900336 private String getSegmentId(Subnet osSubnet) {
337 return osNetworkService.network(osSubnet.getNetworkId()).getProviderSegID();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900338 }
339
340 private void setGatewayIcmpRule(IpAddress gatewayIp, DeviceId deviceId, boolean install) {
341 TrafficSelector selector = DefaultTrafficSelector.builder()
342 .matchEthType(Ethernet.TYPE_IPV4)
343 .matchIPProtocol(IPv4.PROTOCOL_ICMP)
344 .matchIPDst(gatewayIp.toIpPrefix())
345 .build();
346
347 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
348 .setOutput(PortNumber.CONTROLLER)
349 .build();
350
sanghodc375372017-06-08 10:41:30 +0900351 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900352 appId,
353 deviceId,
354 selector,
355 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900356 PRIORITY_ICMP_RULE,
sanghodc375372017-06-08 10:41:30 +0900357 Constants.GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900358 install);
359 }
360
daniel parkee8700b2017-05-11 15:50:03 +0900361 private void setInternalRouterRules(DeviceId deviceId, String srcSegmentId, String dstSegmentId,
362 IpPrefix srcSubnet, IpPrefix dstSubnet,
363 NetworkType networkType, boolean install) {
364 TrafficSelector selector;
365 TrafficTreatment treatment;
366 switch (networkType) {
367 case VXLAN:
368 selector = DefaultTrafficSelector.builder()
369 .matchEthType(Ethernet.TYPE_IPV4)
370 .matchTunnelId(Long.parseLong(srcSegmentId))
371 .matchIPSrc(srcSubnet)
372 .matchIPDst(dstSubnet)
373 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900374
daniel parkee8700b2017-05-11 15:50:03 +0900375 treatment = DefaultTrafficTreatment.builder()
376 .setTunnelId(Long.parseLong(dstSegmentId))
sanghodc375372017-06-08 10:41:30 +0900377 .transition(FORWARDING_TABLE)
daniel parkee8700b2017-05-11 15:50:03 +0900378 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900379
sanghodc375372017-06-08 10:41:30 +0900380 osFlowRuleService.setRule(
daniel parkee8700b2017-05-11 15:50:03 +0900381 appId,
382 deviceId,
383 selector,
384 treatment,
daniel parkee8700b2017-05-11 15:50:03 +0900385 PRIORITY_INTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900386 ROUTING_TABLE,
daniel parkee8700b2017-05-11 15:50:03 +0900387 install);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900388
daniel parkee8700b2017-05-11 15:50:03 +0900389 selector = DefaultTrafficSelector.builder()
390 .matchEthType(Ethernet.TYPE_IPV4)
391 .matchTunnelId(Long.parseLong(dstSegmentId))
392 .matchIPSrc(srcSubnet)
393 .matchIPDst(dstSubnet)
394 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900395
daniel parkee8700b2017-05-11 15:50:03 +0900396 treatment = DefaultTrafficTreatment.builder()
397 .setTunnelId(Long.parseLong(dstSegmentId))
sanghodc375372017-06-08 10:41:30 +0900398 .transition(FORWARDING_TABLE)
daniel parkee8700b2017-05-11 15:50:03 +0900399 .build();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900400
sanghodc375372017-06-08 10:41:30 +0900401 osFlowRuleService.setRule(
daniel parkee8700b2017-05-11 15:50:03 +0900402 appId,
403 deviceId,
404 selector,
405 treatment,
daniel parkee8700b2017-05-11 15:50:03 +0900406 PRIORITY_INTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900407 ROUTING_TABLE,
daniel parkee8700b2017-05-11 15:50:03 +0900408 install);
409 break;
410 case VLAN:
411 selector = DefaultTrafficSelector.builder()
412 .matchEthType(Ethernet.TYPE_IPV4)
413 .matchVlanId(VlanId.vlanId(srcSegmentId))
414 .matchIPSrc(srcSubnet)
415 .matchIPDst(dstSubnet)
416 .build();
417
418 treatment = DefaultTrafficTreatment.builder()
419 .setVlanId(VlanId.vlanId(dstSegmentId))
sanghodc375372017-06-08 10:41:30 +0900420 .transition(FORWARDING_TABLE)
daniel parkee8700b2017-05-11 15:50:03 +0900421 .build();
422
sanghodc375372017-06-08 10:41:30 +0900423 osFlowRuleService.setRule(
daniel parkee8700b2017-05-11 15:50:03 +0900424 appId,
425 deviceId,
426 selector,
427 treatment,
daniel parkee8700b2017-05-11 15:50:03 +0900428 PRIORITY_INTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900429 ROUTING_TABLE,
daniel parkee8700b2017-05-11 15:50:03 +0900430 install);
431
432 selector = DefaultTrafficSelector.builder()
433 .matchEthType(Ethernet.TYPE_IPV4)
434 .matchVlanId(VlanId.vlanId(dstSegmentId))
435 .matchIPSrc(srcSubnet)
436 .matchIPDst(dstSubnet)
437 .build();
438
439 treatment = DefaultTrafficTreatment.builder()
440 .setVlanId(VlanId.vlanId(dstSegmentId))
sanghodc375372017-06-08 10:41:30 +0900441 .transition(FORWARDING_TABLE)
daniel parkee8700b2017-05-11 15:50:03 +0900442 .build();
443
sanghodc375372017-06-08 10:41:30 +0900444 osFlowRuleService.setRule(
daniel parkee8700b2017-05-11 15:50:03 +0900445 appId,
446 deviceId,
447 selector,
448 treatment,
daniel parkee8700b2017-05-11 15:50:03 +0900449 PRIORITY_INTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900450 ROUTING_TABLE,
daniel parkee8700b2017-05-11 15:50:03 +0900451 install);
452 break;
453 default:
454 final String error = String.format(
455 ERR_UNSUPPORTED_NET_TYPE + "%s",
456 networkType.toString());
457 throw new IllegalStateException(error);
458 }
459
Hyunsun Moon44aac662017-02-18 02:07:01 +0900460 }
461
daniel parkee8700b2017-05-11 15:50:03 +0900462 private void setRulesToGateway(DeviceId deviceId, String segmentId, IpPrefix srcSubnet,
463 NetworkType networkType, boolean install) {
464 TrafficTreatment treatment;
465 GroupId groupId;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900466
daniel parkee8700b2017-05-11 15:50:03 +0900467 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
468 .matchEthType(Ethernet.TYPE_IPV4)
469 .matchIPSrc(srcSubnet)
470 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
471
472 switch (networkType) {
473 case VXLAN:
474 sBuilder.matchTunnelId(Long.parseLong(segmentId));
475
476 groupId = osNodeService.gatewayGroupId(deviceId, NetworkMode.VXLAN);
477 break;
478 case VLAN:
479 sBuilder.matchVlanId(VlanId.vlanId(segmentId));
480
481 groupId = osNodeService.gatewayGroupId(deviceId, NetworkMode.VLAN);
482 break;
483 default:
484 final String error = String.format(
485 ERR_UNSUPPORTED_NET_TYPE + "%s",
486 networkType.toString());
487 throw new IllegalStateException(error);
488 }
489
490 treatment = DefaultTrafficTreatment.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900491 .group(groupId)
492 .build();
493
sanghodc375372017-06-08 10:41:30 +0900494 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900495 appId,
496 deviceId,
daniel parkee8700b2017-05-11 15:50:03 +0900497 sBuilder.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900498 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900499 PRIORITY_EXTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900500 ROUTING_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900501 install);
502 }
503
daniel parkee8700b2017-05-11 15:50:03 +0900504 private void setRulesToController(DeviceId deviceId, String segmentId, IpPrefix srcSubnet,
505 NetworkType networkType, boolean install) {
506 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900507 .matchEthType(Ethernet.TYPE_IPV4)
daniel parkee8700b2017-05-11 15:50:03 +0900508 .matchIPSrc(srcSubnet);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900509
daniel parkee8700b2017-05-11 15:50:03 +0900510 switch (networkType) {
511 case VXLAN:
512 sBuilder.matchTunnelId(Long.parseLong(segmentId))
513 .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
514 break;
515 case VLAN:
516 sBuilder.matchVlanId(VlanId.vlanId(segmentId))
517 .matchEthDst(MacAddress.valueOf(vlanPortMac(deviceId)));
518 break;
519 default:
520 final String error = String.format(
521 ERR_UNSUPPORTED_NET_TYPE + "%s",
522 networkType.toString());
523 throw new IllegalStateException(error);
524 }
525
526 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
527 .setEthDst(Constants.DEFAULT_GATEWAY_MAC);
528
529 if (networkType.equals(NetworkType.VLAN)) {
530 tBuilder.popVlan();
531 }
532
533 tBuilder.setOutput(PortNumber.CONTROLLER);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900534
sanghodc375372017-06-08 10:41:30 +0900535 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900536 appId,
537 deviceId,
daniel parkee8700b2017-05-11 15:50:03 +0900538 sBuilder.build(),
539 tBuilder.build(),
Hyunsun Moon44aac662017-02-18 02:07:01 +0900540 PRIORITY_EXTERNAL_ROUTING_RULE,
sanghodc375372017-06-08 10:41:30 +0900541 Constants.GW_COMMON_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900542 install);
543 }
544
daniel parkee8700b2017-05-11 15:50:03 +0900545 private String vlanPortMac(DeviceId deviceId) {
546 return deviceService.getPorts(deviceId).stream()
547 .filter(p -> p.annotations()
548 .value(PORT_NAME).equals(osNodeService.gatewayNode(deviceId).vlanPort().get()) && p.isEnabled())
549 .findFirst().get().annotations().value(PORT_MAC);
550 }
551
552 private void setRulesToGatewayWithDstIp(DeviceId deviceId, GroupId groupId, String segmentId,
553 IpAddress dstIp, NetworkMode networkMode, boolean install) {
554 TrafficSelector selector;
555 if (networkMode.equals(NetworkMode.VXLAN)) {
556 selector = DefaultTrafficSelector.builder()
557 .matchEthType(Ethernet.TYPE_IPV4)
558 .matchTunnelId(Long.valueOf(segmentId))
559 .matchIPDst(dstIp.toIpPrefix())
560 .build();
561 } else {
562 selector = DefaultTrafficSelector.builder()
563 .matchEthType(Ethernet.TYPE_IPV4)
564 .matchVlanId(VlanId.vlanId(segmentId))
565 .matchIPDst(dstIp.toIpPrefix())
566 .build();
567 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900568
569 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
570 .group(groupId)
571 .build();
572
sanghodc375372017-06-08 10:41:30 +0900573 osFlowRuleService.setRule(
Hyunsun Moon44aac662017-02-18 02:07:01 +0900574 appId,
575 deviceId,
576 selector,
577 treatment,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900578 PRIORITY_SWITCHING_RULE,
sanghodc375372017-06-08 10:41:30 +0900579 ROUTING_TABLE,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900580 install);
581 }
582
583 private class InternalRouterEventListener implements OpenstackRouterListener {
584
585 @Override
586 public boolean isRelevant(OpenstackRouterEvent event) {
587 // do not allow to proceed without leadership
588 NodeId leader = leadershipService.getLeader(appId.name());
589 return Objects.equals(localNodeId, leader);
590 }
591
592 // FIXME only one leader in the cluster should process
593 @Override
594 public void event(OpenstackRouterEvent event) {
595 switch (event.type()) {
596 case OPENSTACK_ROUTER_CREATED:
597 log.debug("Router(name:{}, ID:{}) is created",
598 event.subject().getName(),
599 event.subject().getId());
600 eventExecutor.execute(() -> routerUpdated(event.subject()));
601 break;
602 case OPENSTACK_ROUTER_UPDATED:
603 log.debug("Router(name:{}, ID:{}) is updated",
604 event.subject().getName(),
605 event.subject().getId());
606 eventExecutor.execute(() -> routerUpdated(event.subject()));
607 break;
608 case OPENSTACK_ROUTER_REMOVED:
609 log.debug("Router(name:{}, ID:{}) is removed",
610 event.subject().getName(),
611 event.subject().getId());
612 break;
613 case OPENSTACK_ROUTER_INTERFACE_ADDED:
614 log.debug("Router interface {} added to router {}",
615 event.routerIface().getPortId(),
616 event.routerIface().getId());
617 eventExecutor.execute(() -> routerIfaceAdded(
618 event.subject(),
619 event.routerIface()));
620 break;
621 case OPENSTACK_ROUTER_INTERFACE_UPDATED:
622 log.debug("Router interface {} on {} updated",
623 event.routerIface().getPortId(),
624 event.routerIface().getId());
625 break;
626 case OPENSTACK_ROUTER_INTERFACE_REMOVED:
627 log.debug("Router interface {} removed from router {}",
628 event.routerIface().getPortId(),
629 event.routerIface().getId());
630 eventExecutor.execute(() -> routerIfaceRemoved(
631 event.subject(),
632 event.routerIface()));
633 break;
634 case OPENSTACK_ROUTER_GATEWAY_ADDED:
635 case OPENSTACK_ROUTER_GATEWAY_REMOVED:
636 case OPENSTACK_FLOATING_IP_CREATED:
637 case OPENSTACK_FLOATING_IP_UPDATED:
638 case OPENSTACK_FLOATING_IP_REMOVED:
639 case OPENSTACK_FLOATING_IP_ASSOCIATED:
640 case OPENSTACK_FLOATING_IP_DISASSOCIATED:
641 default:
642 // do nothing for the other events
643 break;
644 }
645 }
646 }
647
648 private class InternalNodeEventListener implements OpenstackNodeListener {
649
650 @Override
651 public boolean isRelevant(OpenstackNodeEvent event) {
652 // do not allow to proceed without leadership
653 NodeId leader = leadershipService.getLeader(appId.name());
654 return Objects.equals(localNodeId, leader);
655 }
656
657 @Override
658 public void event(OpenstackNodeEvent event) {
659 OpenstackNode osNode = event.subject();
660
661 switch (event.type()) {
662 case COMPLETE:
663 case INCOMPLETE:
664 eventExecutor.execute(() -> {
Hyunsun Moon0e058f22017-04-19 17:00:52 +0900665 log.info("Reconfigure routers for {}", osNode.hostname());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900666 reconfigureRouters();
667 });
668 break;
669 case INIT:
670 case DEVICE_CREATED:
671 default:
672 break;
673 }
674 }
675
676 private void reconfigureRouters() {
677 osRouterService.routers().forEach(osRouter -> {
678 routerUpdated(osRouter);
679 osRouterService.routerInterfaces(osRouter.getId()).forEach(iface -> {
680 routerIfaceAdded(osRouter, iface);
681 });
682 });
683 }
684 }
685}