blob: 98fdbd9cc64458cda7f496b438d57530a9cd9fd7 [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 parkb5817102018-02-15 00:18:51 +090029import org.onosproject.net.PortNumber;
Daniel Park81a61a12016-02-26 08:24:44 +090030import org.onosproject.net.flow.DefaultTrafficTreatment;
Daniel Park81a61a12016-02-26 08:24:44 +090031import org.onosproject.net.flow.TrafficTreatment;
32import org.onosproject.net.packet.DefaultOutboundPacket;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070033import org.onosproject.net.packet.InboundPacket;
Daniel Park81a61a12016-02-26 08:24:44 +090034import org.onosproject.net.packet.PacketContext;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070035import org.onosproject.net.packet.PacketProcessor;
Daniel Park81a61a12016-02-26 08:24:44 +090036import org.onosproject.net.packet.PacketService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090037import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Hyunsun Moon05400872017-02-07 17:11:25 +090038import org.onosproject.openstacknetworking.api.Constants;
Hyunsun Moon0d457362017-06-27 17:19:41 +090039import org.onosproject.openstacknode.api.OpenstackNode;
40import org.onosproject.openstacknode.api.OpenstackNodeService;
Daniel Park81a61a12016-02-26 08:24:44 +090041import org.slf4j.Logger;
42
43import java.nio.ByteBuffer;
Hyunsun Moon44aac662017-02-18 02:07:01 +090044import java.util.Objects;
Hyunsun Moon0d457362017-06-27 17:19:41 +090045import java.util.Set;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070046import java.util.concurrent.ExecutorService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090047import java.util.stream.Collectors;
Daniel Park81a61a12016-02-26 08:24:44 +090048
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070049import static java.util.concurrent.Executors.newSingleThreadExecutor;
50import static org.onlab.util.Tools.groupedThreads;
Hyunsun Moon0d457362017-06-27 17:19:41 +090051import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Daniel Park81a61a12016-02-26 08:24:44 +090052import static org.slf4j.LoggerFactory.getLogger;
53
54/**
Hyunsun Moon44aac662017-02-18 02:07:01 +090055 * Handle ARP requests from gateway nodes.
Daniel Park81a61a12016-02-26 08:24:44 +090056 */
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070057@Component(immediate = true)
Daniel Park81a61a12016-02-26 08:24:44 +090058public class OpenstackRoutingArpHandler {
Hyunsun Moon44aac662017-02-18 02:07:01 +090059
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070060 private final Logger log = getLogger(getClass());
Daniel Park81a61a12016-02-26 08:24:44 +090061
Hyunsun Moon44aac662017-02-18 02:07:01 +090062 private static final String DEVICE_OWNER_ROUTER_GW = "network:router_gateway";
63 private static final String DEVICE_OWNER_FLOATING_IP = "network:floatingip";
64
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070065 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
66 protected PacketService packetService;
Daniel Park81a61a12016-02-26 08:24:44 +090067
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070068 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
daniel parke49eb382017-04-05 16:48:28 +090069 protected OpenstackNetworkService osNetworkService;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070070
Hyunsun Moon44aac662017-02-18 02:07:01 +090071 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
daniel parke49eb382017-04-05 16:48:28 +090072 protected OpenstackNodeService osNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090073
74 private final ExecutorService eventExecutor = newSingleThreadExecutor(
75 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070076
Hyunsun Moon0d457362017-06-27 17:19:41 +090077 private final PacketProcessor packetProcessor = new InternalPacketProcessor();
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070078
79 @Activate
80 protected void activate() {
81 packetService.addProcessor(packetProcessor, PacketProcessor.director(1));
82 log.info("Started");
Daniel Park81a61a12016-02-26 08:24:44 +090083 }
84
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070085 @Deactivate
86 protected void deactivate() {
87 packetService.removeProcessor(packetProcessor);
Hyunsun Moon44aac662017-02-18 02:07:01 +090088 eventExecutor.shutdown();
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070089 log.info("Stopped");
Daniel Park81a61a12016-02-26 08:24:44 +090090 }
91
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070092 private void processArpPacket(PacketContext context, Ethernet ethernet) {
Daniel Park81a61a12016-02-26 08:24:44 +090093 ARP arp = (ARP) ethernet.getPayload();
daniel parkb5817102018-02-15 00:18:51 +090094 if (arp.getOpCode() == ARP.OP_REQUEST) {
95 if (log.isTraceEnabled()) {
96 log.trace("ARP request received from {} for {}",
97 Ip4Address.valueOf(arp.getSenderProtocolAddress()).toString(),
98 Ip4Address.valueOf(arp.getTargetProtocolAddress()).toString());
99 }
100
101 IpAddress targetIp = Ip4Address.valueOf(arp.getTargetProtocolAddress());
102 if (!isServiceIp(targetIp.getIp4Address())) {
103 log.trace("Unknown target ARP request for {}, ignore it", targetIp);
104 return;
105 }
106
107 MacAddress targetMac = Constants.DEFAULT_EXTERNAL_ROUTER_MAC;
108 Ethernet ethReply = ARP.buildArpReply(targetIp.getIp4Address(),
109 targetMac, ethernet);
110
111 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
112 .setOutput(context.inPacket().receivedFrom().port())
113 .build();
114
115 packetService.emit(new DefaultOutboundPacket(
116 context.inPacket().receivedFrom().deviceId(),
117 treatment,
118 ByteBuffer.wrap(ethReply.serialize())));
119
120 context.block();
121 } else if (arp.getOpCode() == ARP.OP_REPLY) {
122 PortNumber receivedPortNum = context.inPacket().receivedFrom().port();
123 log.debug("ARP reply ip: {}, mac: {}",
124 Ip4Address.valueOf(arp.getSenderProtocolAddress()),
125 MacAddress.valueOf(arp.getSenderHardwareAddress()));
126 try {
127 if (receivedPortNum.equals(
128 osNodeService.node(context.inPacket().receivedFrom().deviceId()).uplinkPortNum())) {
129 osNetworkService.updateExternalPeerRouterMac(
130 Ip4Address.valueOf(arp.getSenderProtocolAddress()),
131 MacAddress.valueOf(arp.getSenderHardwareAddress()));
132 }
133 } catch (Exception e) {
134 log.error("Exception occurred because of {}", e.toString());
135 }
Daniel Park81a61a12016-02-26 08:24:44 +0900136 }
137
Daniel Park81a61a12016-02-26 08:24:44 +0900138 }
139
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700140 private class InternalPacketProcessor implements PacketProcessor {
141
142 @Override
143 public void process(PacketContext context) {
144 if (context.isHandled()) {
145 return;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900146 }
147
148 Set<DeviceId> gateways = osNodeService.completeNodes(GATEWAY)
149 .stream().map(OpenstackNode::intgBridge)
150 .collect(Collectors.toSet());
151
152 if (!gateways.contains(context.inPacket().receivedFrom().deviceId())) {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700153 // return if the packet is not from gateway nodes
154 return;
155 }
156
157 InboundPacket pkt = context.inPacket();
158 Ethernet ethernet = pkt.parsed();
159 if (ethernet != null &&
160 ethernet.getEtherType() == Ethernet.TYPE_ARP) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900161 eventExecutor.execute(() -> processArpPacket(context, ethernet));
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700162 }
163 }
164 }
165
Hyunsun Moon44aac662017-02-18 02:07:01 +0900166 private boolean isServiceIp(IpAddress targetIp) {
167 // FIXME use floating IP and external gateway information of router instead
168 // once openstack4j fixed
169 return osNetworkService.ports().stream()
170 .filter(osPort -> Objects.equals(osPort.getDeviceOwner(),
171 DEVICE_OWNER_ROUTER_GW) ||
172 Objects.equals(osPort.getDeviceOwner(),
173 DEVICE_OWNER_FLOATING_IP))
174 .flatMap(osPort -> osPort.getFixedIps().stream())
175 .anyMatch(ip -> IpAddress.valueOf(ip.getIpAddress()).equals(targetIp));
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900176 }
Daniel Park81a61a12016-02-26 08:24:44 +0900177}