blob: 657d7a0ba40a6e5d30b879e838bf444d8f6aa385 [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 Moon05400872017-02-07 17:11:25 +090037import org.onosproject.openstacknetworking.api.Constants;
daniel park576969a2018-03-09 07:07:41 +090038import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
daniel parkeeb8e042018-02-21 14:06:58 +090039import org.onosproject.openstacknetworking.api.OpenstackRouterService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090040import org.onosproject.openstacknode.api.OpenstackNode;
41import org.onosproject.openstacknode.api.OpenstackNodeService;
daniel parkeeb8e042018-02-21 14:06:58 +090042import org.openstack4j.model.network.NetFloatingIP;
Daniel Park81a61a12016-02-26 08:24:44 +090043import org.slf4j.Logger;
44
45import java.nio.ByteBuffer;
Hyunsun Moon44aac662017-02-18 02:07:01 +090046import java.util.Objects;
Hyunsun Moon0d457362017-06-27 17:19:41 +090047import java.util.Set;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070048import java.util.concurrent.ExecutorService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090049import java.util.stream.Collectors;
Daniel Park81a61a12016-02-26 08:24:44 +090050
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070051import static java.util.concurrent.Executors.newSingleThreadExecutor;
52import static org.onlab.util.Tools.groupedThreads;
Hyunsun Moon0d457362017-06-27 17:19:41 +090053import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Daniel Park81a61a12016-02-26 08:24:44 +090054import static org.slf4j.LoggerFactory.getLogger;
55
56/**
Hyunsun Moon44aac662017-02-18 02:07:01 +090057 * Handle ARP requests from gateway nodes.
Daniel Park81a61a12016-02-26 08:24:44 +090058 */
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070059@Component(immediate = true)
Daniel Park81a61a12016-02-26 08:24:44 +090060public class OpenstackRoutingArpHandler {
Hyunsun Moon44aac662017-02-18 02:07:01 +090061
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070062 private final Logger log = getLogger(getClass());
Daniel Park81a61a12016-02-26 08:24:44 +090063
Hyunsun Moon44aac662017-02-18 02:07:01 +090064 private static final String DEVICE_OWNER_ROUTER_GW = "network:router_gateway";
65 private static final String DEVICE_OWNER_FLOATING_IP = "network:floatingip";
66
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070067 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
68 protected PacketService packetService;
Daniel Park81a61a12016-02-26 08:24:44 +090069
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070070 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
daniel parke49eb382017-04-05 16:48:28 +090071 protected OpenstackNetworkService osNetworkService;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070072
Hyunsun Moon44aac662017-02-18 02:07:01 +090073 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
daniel parkeeb8e042018-02-21 14:06:58 +090074 protected OpenstackRouterService osRouterService;
75
76
77 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
daniel parke49eb382017-04-05 16:48:28 +090078 protected OpenstackNodeService osNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090079
80 private final ExecutorService eventExecutor = newSingleThreadExecutor(
81 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070082
Hyunsun Moon0d457362017-06-27 17:19:41 +090083 private final PacketProcessor packetProcessor = new InternalPacketProcessor();
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070084
85 @Activate
86 protected void activate() {
87 packetService.addProcessor(packetProcessor, PacketProcessor.director(1));
88 log.info("Started");
Daniel Park81a61a12016-02-26 08:24:44 +090089 }
90
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070091 @Deactivate
92 protected void deactivate() {
93 packetService.removeProcessor(packetProcessor);
Hyunsun Moon44aac662017-02-18 02:07:01 +090094 eventExecutor.shutdown();
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070095 log.info("Stopped");
Daniel Park81a61a12016-02-26 08:24:44 +090096 }
97
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070098 private void processArpPacket(PacketContext context, Ethernet ethernet) {
Daniel Park81a61a12016-02-26 08:24:44 +090099 ARP arp = (ARP) ethernet.getPayload();
daniel parkb5817102018-02-15 00:18:51 +0900100 if (arp.getOpCode() == ARP.OP_REQUEST) {
101 if (log.isTraceEnabled()) {
102 log.trace("ARP request received from {} for {}",
103 Ip4Address.valueOf(arp.getSenderProtocolAddress()).toString(),
104 Ip4Address.valueOf(arp.getTargetProtocolAddress()).toString());
105 }
106
107 IpAddress targetIp = Ip4Address.valueOf(arp.getTargetProtocolAddress());
daniel parkeeb8e042018-02-21 14:06:58 +0900108
109 MacAddress targetMac = null;
110
111 NetFloatingIP floatingIP = osRouterService.floatingIps().stream()
112 .filter(ip -> ip.getFloatingIpAddress().equals(targetIp.toString()))
113 .findAny().orElse(null);
114
daniel park576969a2018-03-09 07:07:41 +0900115 //In case target ip is for associated floating ip, sets target mac to vm's.
daniel parkeeb8e042018-02-21 14:06:58 +0900116 if (floatingIP != null && floatingIP.getPortId() != null) {
117 targetMac = MacAddress.valueOf(osNetworkService.port(floatingIP.getPortId()).getMacAddress());
118 }
119
120 if (isExternalGatewaySourceIp(targetIp.getIp4Address())) {
121 targetMac = Constants.DEFAULT_GATEWAY_MAC;
122 }
123
124 if (targetMac == null) {
daniel parkb5817102018-02-15 00:18:51 +0900125 log.trace("Unknown target ARP request for {}, ignore it", targetIp);
126 return;
127 }
128
daniel parkb5817102018-02-15 00:18:51 +0900129 Ethernet ethReply = ARP.buildArpReply(targetIp.getIp4Address(),
130 targetMac, ethernet);
131
daniel park576969a2018-03-09 07:07:41 +0900132
daniel parkb5817102018-02-15 00:18:51 +0900133 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
daniel park576969a2018-03-09 07:07:41 +0900134 .setOutput(context.inPacket().receivedFrom().port()).build();
daniel parkb5817102018-02-15 00:18:51 +0900135
136 packetService.emit(new DefaultOutboundPacket(
137 context.inPacket().receivedFrom().deviceId(),
138 treatment,
139 ByteBuffer.wrap(ethReply.serialize())));
140
141 context.block();
142 } else if (arp.getOpCode() == ARP.OP_REPLY) {
143 PortNumber receivedPortNum = context.inPacket().receivedFrom().port();
144 log.debug("ARP reply ip: {}, mac: {}",
145 Ip4Address.valueOf(arp.getSenderProtocolAddress()),
146 MacAddress.valueOf(arp.getSenderHardwareAddress()));
147 try {
148 if (receivedPortNum.equals(
149 osNodeService.node(context.inPacket().receivedFrom().deviceId()).uplinkPortNum())) {
150 osNetworkService.updateExternalPeerRouterMac(
151 Ip4Address.valueOf(arp.getSenderProtocolAddress()),
152 MacAddress.valueOf(arp.getSenderHardwareAddress()));
153 }
154 } catch (Exception e) {
155 log.error("Exception occurred because of {}", e.toString());
156 }
Daniel Park81a61a12016-02-26 08:24:44 +0900157 }
158
Daniel Park81a61a12016-02-26 08:24:44 +0900159 }
160
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700161 private class InternalPacketProcessor implements PacketProcessor {
162
163 @Override
164 public void process(PacketContext context) {
165 if (context.isHandled()) {
166 return;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900167 }
168
169 Set<DeviceId> gateways = osNodeService.completeNodes(GATEWAY)
170 .stream().map(OpenstackNode::intgBridge)
171 .collect(Collectors.toSet());
172
173 if (!gateways.contains(context.inPacket().receivedFrom().deviceId())) {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700174 // return if the packet is not from gateway nodes
175 return;
176 }
177
178 InboundPacket pkt = context.inPacket();
179 Ethernet ethernet = pkt.parsed();
180 if (ethernet != null &&
181 ethernet.getEtherType() == Ethernet.TYPE_ARP) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900182 eventExecutor.execute(() -> processArpPacket(context, ethernet));
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700183 }
184 }
185 }
186
daniel parkeeb8e042018-02-21 14:06:58 +0900187 private boolean isExternalGatewaySourceIp(IpAddress targetIp) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900188 return osNetworkService.ports().stream()
189 .filter(osPort -> Objects.equals(osPort.getDeviceOwner(),
daniel parkeeb8e042018-02-21 14:06:58 +0900190 DEVICE_OWNER_ROUTER_GW))
Hyunsun Moon44aac662017-02-18 02:07:01 +0900191 .flatMap(osPort -> osPort.getFixedIps().stream())
192 .anyMatch(ip -> IpAddress.valueOf(ip.getIpAddress()).equals(targetIp));
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900193 }
Daniel Park81a61a12016-02-26 08:24:44 +0900194}