blob: c527f9e5d380ae1979a8e5a0bdf52b778f41da52 [file] [log] [blame]
Daniel Park81a61a12016-02-26 08:24:44 +09001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Daniel Park81a61a12016-02-26 08:24:44 +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 */
Hyunsun Moon05400872017-02-07 17:11:25 +090016package org.onosproject.openstacknetworking.impl;
Daniel Park81a61a12016-02-26 08:24:44 +090017
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070018import org.apache.felix.scr.annotations.Activate;
19import org.apache.felix.scr.annotations.Component;
20import org.apache.felix.scr.annotations.Deactivate;
21import org.apache.felix.scr.annotations.Reference;
22import org.apache.felix.scr.annotations.ReferenceCardinality;
Daniel Park81a61a12016-02-26 08:24:44 +090023import org.onlab.packet.ARP;
Daniel Park81a61a12016-02-26 08:24:44 +090024import org.onlab.packet.Ethernet;
Daniel Park81a61a12016-02-26 08:24:44 +090025import org.onlab.packet.Ip4Address;
26import org.onlab.packet.IpAddress;
27import org.onlab.packet.MacAddress;
Hyunsun Moon0d457362017-06-27 17:19:41 +090028import org.onosproject.net.DeviceId;
Daniel Park81a61a12016-02-26 08:24:44 +090029import org.onosproject.net.flow.DefaultTrafficTreatment;
Daniel Park81a61a12016-02-26 08:24:44 +090030import org.onosproject.net.flow.TrafficTreatment;
31import org.onosproject.net.packet.DefaultOutboundPacket;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070032import org.onosproject.net.packet.InboundPacket;
Daniel Park81a61a12016-02-26 08:24:44 +090033import org.onosproject.net.packet.PacketContext;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070034import org.onosproject.net.packet.PacketProcessor;
Daniel Park81a61a12016-02-26 08:24:44 +090035import org.onosproject.net.packet.PacketService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090036import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Hyunsun Moon05400872017-02-07 17:11:25 +090037import org.onosproject.openstacknetworking.api.Constants;
Hyunsun Moon0d457362017-06-27 17:19:41 +090038import org.onosproject.openstacknode.api.OpenstackNode;
39import org.onosproject.openstacknode.api.OpenstackNodeService;
Daniel Park81a61a12016-02-26 08:24:44 +090040import org.slf4j.Logger;
41
42import java.nio.ByteBuffer;
Hyunsun Moon44aac662017-02-18 02:07:01 +090043import java.util.Objects;
Hyunsun Moon0d457362017-06-27 17:19:41 +090044import java.util.Set;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070045import java.util.concurrent.ExecutorService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090046import java.util.stream.Collectors;
Daniel Park81a61a12016-02-26 08:24:44 +090047
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070048import static java.util.concurrent.Executors.newSingleThreadExecutor;
49import static org.onlab.util.Tools.groupedThreads;
Hyunsun Moon0d457362017-06-27 17:19:41 +090050import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Daniel Park81a61a12016-02-26 08:24:44 +090051import static org.slf4j.LoggerFactory.getLogger;
52
53/**
Hyunsun Moon44aac662017-02-18 02:07:01 +090054 * Handle ARP requests from gateway nodes.
Daniel Park81a61a12016-02-26 08:24:44 +090055 */
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070056@Component(immediate = true)
Daniel Park81a61a12016-02-26 08:24:44 +090057public class OpenstackRoutingArpHandler {
Hyunsun Moon44aac662017-02-18 02:07:01 +090058
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070059 private final Logger log = getLogger(getClass());
Daniel Park81a61a12016-02-26 08:24:44 +090060
Hyunsun Moon44aac662017-02-18 02:07:01 +090061 private static final String DEVICE_OWNER_ROUTER_GW = "network:router_gateway";
62 private static final String DEVICE_OWNER_FLOATING_IP = "network:floatingip";
63
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070064 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
65 protected PacketService packetService;
Daniel Park81a61a12016-02-26 08:24:44 +090066
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070067 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
daniel parke49eb382017-04-05 16:48:28 +090068 protected OpenstackNetworkService osNetworkService;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070069
Hyunsun Moon44aac662017-02-18 02:07:01 +090070 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
daniel parke49eb382017-04-05 16:48:28 +090071 protected OpenstackNodeService osNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090072
73 private final ExecutorService eventExecutor = newSingleThreadExecutor(
74 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070075
Hyunsun Moon0d457362017-06-27 17:19:41 +090076 private final PacketProcessor packetProcessor = new InternalPacketProcessor();
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070077
78 @Activate
79 protected void activate() {
80 packetService.addProcessor(packetProcessor, PacketProcessor.director(1));
81 log.info("Started");
Daniel Park81a61a12016-02-26 08:24:44 +090082 }
83
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070084 @Deactivate
85 protected void deactivate() {
86 packetService.removeProcessor(packetProcessor);
Hyunsun Moon44aac662017-02-18 02:07:01 +090087 eventExecutor.shutdown();
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070088 log.info("Stopped");
Daniel Park81a61a12016-02-26 08:24:44 +090089 }
90
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070091 private void processArpPacket(PacketContext context, Ethernet ethernet) {
Daniel Park81a61a12016-02-26 08:24:44 +090092 ARP arp = (ARP) ethernet.getPayload();
Daniel Park81a61a12016-02-26 08:24:44 +090093 if (arp.getOpCode() != ARP.OP_REQUEST) {
94 return;
95 }
96
Hyunsun Moon44aac662017-02-18 02:07:01 +090097 if (log.isTraceEnabled()) {
98 log.trace("ARP request received from {} for {}",
99 Ip4Address.valueOf(arp.getSenderProtocolAddress()).toString(),
100 Ip4Address.valueOf(arp.getTargetProtocolAddress()).toString());
101 }
102
Daniel Park81a61a12016-02-26 08:24:44 +0900103 IpAddress targetIp = Ip4Address.valueOf(arp.getTargetProtocolAddress());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900104 if (!isServiceIp(targetIp.getIp4Address())) {
105 log.trace("Unknown target ARP request for {}, ignore it", targetIp);
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700106 return;
Daniel Park81a61a12016-02-26 08:24:44 +0900107 }
108
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700109 MacAddress targetMac = Constants.DEFAULT_EXTERNAL_ROUTER_MAC;
Daniel Park81a61a12016-02-26 08:24:44 +0900110 Ethernet ethReply = ARP.buildArpReply(targetIp.getIp4Address(),
111 targetMac, ethernet);
112
113 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
114 .setOutput(context.inPacket().receivedFrom().port())
115 .build();
116
117 packetService.emit(new DefaultOutboundPacket(
118 context.inPacket().receivedFrom().deviceId(),
119 treatment,
120 ByteBuffer.wrap(ethReply.serialize())));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900121
122 context.block();
Daniel Park81a61a12016-02-26 08:24:44 +0900123 }
124
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700125 private class InternalPacketProcessor implements PacketProcessor {
126
127 @Override
128 public void process(PacketContext context) {
129 if (context.isHandled()) {
130 return;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900131 }
132
133 Set<DeviceId> gateways = osNodeService.completeNodes(GATEWAY)
134 .stream().map(OpenstackNode::intgBridge)
135 .collect(Collectors.toSet());
136
137 if (!gateways.contains(context.inPacket().receivedFrom().deviceId())) {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700138 // return if the packet is not from gateway nodes
139 return;
140 }
141
142 InboundPacket pkt = context.inPacket();
143 Ethernet ethernet = pkt.parsed();
144 if (ethernet != null &&
145 ethernet.getEtherType() == Ethernet.TYPE_ARP) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900146 eventExecutor.execute(() -> processArpPacket(context, ethernet));
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700147 }
148 }
149 }
150
Hyunsun Moon44aac662017-02-18 02:07:01 +0900151 private boolean isServiceIp(IpAddress targetIp) {
152 // FIXME use floating IP and external gateway information of router instead
153 // once openstack4j fixed
154 return osNetworkService.ports().stream()
155 .filter(osPort -> Objects.equals(osPort.getDeviceOwner(),
156 DEVICE_OWNER_ROUTER_GW) ||
157 Objects.equals(osPort.getDeviceOwner(),
158 DEVICE_OWNER_FLOATING_IP))
159 .flatMap(osPort -> osPort.getFixedIps().stream())
160 .anyMatch(ip -> IpAddress.valueOf(ip.getIpAddress()).equals(targetIp));
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900161 }
Daniel Park81a61a12016-02-26 08:24:44 +0900162}