blob: 1031f191bea72690ef0c4d3d107c0e954bc166d5 [file] [log] [blame]
Hyunsun Moonb974fca2016-06-30 21:20:39 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002* Copyright 2016-present Open Networking Foundation
Hyunsun Moonb974fca2016-06-30 21:20:39 -07003*
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;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070017
18import com.google.common.base.Strings;
19import com.google.common.collect.Sets;
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.Modified;
24import org.apache.felix.scr.annotations.Property;
25import org.apache.felix.scr.annotations.Reference;
26import org.apache.felix.scr.annotations.ReferenceCardinality;
27import org.onlab.packet.ARP;
Hyunsun Moon44aac662017-02-18 02:07:01 +090028import org.onlab.packet.EthType;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070029import org.onlab.packet.Ethernet;
30import org.onlab.packet.Ip4Address;
31import org.onlab.packet.IpAddress;
32import org.onlab.packet.MacAddress;
33import org.onlab.util.Tools;
Hyunsun Moon44aac662017-02-18 02:07:01 +090034import org.onosproject.cfg.ComponentConfigService;
35import org.onosproject.core.ApplicationId;
36import org.onosproject.core.CoreService;
37import org.onosproject.net.flow.DefaultTrafficSelector;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070038import org.onosproject.net.flow.DefaultTrafficTreatment;
Hyunsun Moon44aac662017-02-18 02:07:01 +090039import org.onosproject.net.flow.TrafficSelector;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070040import org.onosproject.net.flow.TrafficTreatment;
41import org.onosproject.net.packet.DefaultOutboundPacket;
42import org.onosproject.net.packet.PacketContext;
Hyunsun Moon44aac662017-02-18 02:07:01 +090043import org.onosproject.net.packet.PacketPriority;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070044import org.onosproject.net.packet.PacketProcessor;
45import org.onosproject.net.packet.PacketService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090046import org.onosproject.openstacknetworking.api.InstancePort;
47import org.onosproject.openstacknetworking.api.InstancePortService;
48import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
49import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
50import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
51import org.openstack4j.model.network.Subnet;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070052import org.osgi.service.component.ComponentContext;
53import org.slf4j.Logger;
54import org.slf4j.LoggerFactory;
Hyunsun Moon44aac662017-02-18 02:07:01 +090055
Hyunsun Moonb974fca2016-06-30 21:20:39 -070056import java.nio.ByteBuffer;
57import java.util.Dictionary;
58import java.util.Set;
59
60import static com.google.common.base.Preconditions.checkNotNull;
Hyunsun Moon44aac662017-02-18 02:07:01 +090061import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_GATEWAY_MAC_STR;
62import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070063
64/**
65 * Handles ARP packet from VMs.
66 */
67@Component(immediate = true)
Hyunsun Moon44aac662017-02-18 02:07:01 +090068public final class OpenstackSwitchingArpHandler {
Hyunsun Moonb974fca2016-06-30 21:20:39 -070069
70 private final Logger log = LoggerFactory.getLogger(getClass());
71
72 private static final String GATEWAY_MAC = "gatewayMac";
Hyunsun Moonb974fca2016-06-30 21:20:39 -070073
74 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon44aac662017-02-18 02:07:01 +090075 protected CoreService coreService;
76
77 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moonb974fca2016-06-30 21:20:39 -070078 protected PacketService packetService;
79
80 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon44aac662017-02-18 02:07:01 +090081 protected ComponentConfigService configService;
82
83 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
84 protected InstancePortService instancePortService;
85
86 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
87 protected OpenstackNetworkService osNetworkService;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070088
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070089 @Property(name = GATEWAY_MAC, value = DEFAULT_GATEWAY_MAC_STR,
Hyunsun Moonb974fca2016-06-30 21:20:39 -070090 label = "Fake MAC address for virtual network subnet gateway")
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070091 private String gatewayMac = DEFAULT_GATEWAY_MAC_STR;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070092
93 private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
Hyunsun Moon44aac662017-02-18 02:07:01 +090094 private final InternalOpenstackNetworkListener osNetworkListener =
95 new InternalOpenstackNetworkListener();
96 private final Set<IpAddress> gateways = Sets.newConcurrentHashSet();
97
98 private ApplicationId appId;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070099
100 @Activate
101 protected void activate() {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900102 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
103 configService.registerProperties(getClass());
104 osNetworkService.addListener(osNetworkListener);
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700105 packetService.addProcessor(packetProcessor, PacketProcessor.director(0));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900106 osNetworkService.subnets().forEach(this::addSubnetGateway);
107 requestPacket();
108
109 log.info("Started");
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700110 }
111
112 @Deactivate
113 protected void deactivate() {
114 packetService.removeProcessor(packetProcessor);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900115 osNetworkService.removeListener(osNetworkListener);
116 configService.unregisterProperties(getClass(), false);
117
118 log.info("Stopped");
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700119 }
120
121 @Modified
122 protected void modified(ComponentContext context) {
123 Dictionary<?, ?> properties = context.getProperties();
124 String updatedMac;
125
126 updatedMac = Tools.get(properties, GATEWAY_MAC);
127 if (!Strings.isNullOrEmpty(updatedMac) && !updatedMac.equals(gatewayMac)) {
128 gatewayMac = updatedMac;
129 }
130
131 log.info("Modified");
132 }
133
Hyunsun Moon44aac662017-02-18 02:07:01 +0900134 private void requestPacket() {
135 TrafficSelector selector = DefaultTrafficSelector.builder()
136 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
137 .build();
138
139 packetService.requestPackets(
140 selector,
141 PacketPriority.CONTROL,
142 appId);
143 }
144
145 private void addSubnetGateway(Subnet osSubnet) {
146 if (Strings.isNullOrEmpty(osSubnet.getGateway())) {
147 return;
148 }
149 IpAddress gatewayIp = IpAddress.valueOf(osSubnet.getGateway());
150 gateways.add(gatewayIp);
151 log.debug("Added ARP proxy entry IP:{}", gatewayIp);
152 }
153
154 private void removeSubnetGateway(Subnet osSubnet) {
155 if (Strings.isNullOrEmpty(osSubnet.getGateway())) {
156 return;
157 }
158 IpAddress gatewayIp = IpAddress.valueOf(osSubnet.getGateway());
159 gateways.remove(gatewayIp);
160 log.debug("Removed ARP proxy entry IP:{}", gatewayIp);
161 }
162
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700163 /**
164 * Processes ARP request packets.
165 * It checks if the target IP is owned by a known host first and then ask to
166 * OpenStack if it's not. This ARP proxy does not support overlapping IP.
167 *
Hyunsun Moon44aac662017-02-18 02:07:01 +0900168 * @param context packet context
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700169 * @param ethPacket ethernet packet
170 */
171 private void processPacketIn(PacketContext context, Ethernet ethPacket) {
172 ARP arpPacket = (ARP) ethPacket.getPayload();
173 if (arpPacket.getOpCode() != ARP.OP_REQUEST) {
174 return;
175 }
176
Hyunsun Moon44aac662017-02-18 02:07:01 +0900177 InstancePort srcInstPort = instancePortService.instancePort(ethPacket.getSourceMAC());
178 if (srcInstPort == null) {
179 log.trace("Failed to find source instance port(MAC:{})",
180 ethPacket.getSourceMAC());
181 return;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700182 }
183
Hyunsun Moon44aac662017-02-18 02:07:01 +0900184 IpAddress targetIp = Ip4Address.valueOf(arpPacket.getTargetProtocolAddress());
185 MacAddress replyMac = gateways.contains(targetIp) ? MacAddress.valueOf(gatewayMac) :
186 getMacFromHostOpenstack(targetIp, srcInstPort.networkId());
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700187 if (replyMac == MacAddress.NONE) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900188 log.trace("Failed to find MAC address for {}", targetIp);
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700189 return;
190 }
191
192 Ethernet ethReply = ARP.buildArpReply(
193 targetIp.getIp4Address(),
194 replyMac,
195 ethPacket);
196
197 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
198 .setOutput(context.inPacket().receivedFrom().port())
199 .build();
200
201 packetService.emit(new DefaultOutboundPacket(
202 context.inPacket().receivedFrom().deviceId(),
203 treatment,
204 ByteBuffer.wrap(ethReply.serialize())));
205 }
206
207 /**
208 * Returns MAC address of a host with a given target IP address by asking to
Hyunsun Moon44aac662017-02-18 02:07:01 +0900209 * instance port service.
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700210 *
211 * @param targetIp target ip
Hyunsun Moon44aac662017-02-18 02:07:01 +0900212 * @param osNetId openstack network id of the source instance port
213 * @return mac address, or none mac address if it fails to find the mac
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700214 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900215 private MacAddress getMacFromHostOpenstack(IpAddress targetIp, String osNetId) {
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700216 checkNotNull(targetIp);
217
Hyunsun Moon44aac662017-02-18 02:07:01 +0900218 InstancePort instPort = instancePortService.instancePort(targetIp, osNetId);
219 if (instPort != null) {
220 log.trace("Found MAC from host service for {}", targetIp);
221 return instPort.macAddress();
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700222 } else {
223 return MacAddress.NONE;
224 }
225 }
226
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700227 private class InternalPacketProcessor implements PacketProcessor {
228
229 @Override
230 public void process(PacketContext context) {
231 if (context.isHandled()) {
232 return;
233 }
234
235 Ethernet ethPacket = context.inPacket().parsed();
236 if (ethPacket == null || ethPacket.getEtherType() != Ethernet.TYPE_ARP) {
237 return;
238 }
239 processPacketIn(context, ethPacket);
240 }
241 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900242
243 private class InternalOpenstackNetworkListener implements OpenstackNetworkListener {
244
245 @Override
246 public boolean isRelevant(OpenstackNetworkEvent event) {
247 Subnet osSubnet = event.subnet();
248 if (osSubnet == null) {
249 return false;
250 }
251 return !Strings.isNullOrEmpty(osSubnet.getGateway());
252 }
253
254 @Override
255 public void event(OpenstackNetworkEvent event) {
256 switch (event.type()) {
257 case OPENSTACK_SUBNET_CREATED:
258 case OPENSTACK_SUBNET_UPDATED:
259 addSubnetGateway(event.subnet());
260 break;
261 case OPENSTACK_SUBNET_REMOVED:
262 removeSubnetGateway(event.subnet());
263 break;
264 case OPENSTACK_NETWORK_CREATED:
265 case OPENSTACK_NETWORK_UPDATED:
266 case OPENSTACK_NETWORK_REMOVED:
267 case OPENSTACK_PORT_CREATED:
268 case OPENSTACK_PORT_UPDATED:
269 case OPENSTACK_PORT_REMOVED:
270 default:
271 // do nothing for the other events
272 break;
273 }
274 }
275 }
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700276}