blob: 2eb96df20f9a78e19099abba32324b9eda65d1c6 [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Ray Milkey34c95902015-04-15 09:47:53 -07002 * Copyright 2014-2015 Open Networking Laboratory
Thomas Vachuska781d18b2014-10-27 10:31:25 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * 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
Thomas Vachuska781d18b2014-10-27 10:31:25 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * 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.
Thomas Vachuska781d18b2014-10-27 10:31:25 -070015 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.proxyarp;
alshabibc274c902014-10-03 14:58:27 -070017
alshabibc274c902014-10-03 14:58:27 -070018import org.apache.felix.scr.annotations.Activate;
19import org.apache.felix.scr.annotations.Component;
20import org.apache.felix.scr.annotations.Deactivate;
Pavlin Radoslavov93b606b2015-02-25 17:28:39 -080021import org.apache.felix.scr.annotations.Modified;
22import org.apache.felix.scr.annotations.Property;
alshabibc274c902014-10-03 14:58:27 -070023import org.apache.felix.scr.annotations.Reference;
24import org.apache.felix.scr.annotations.ReferenceCardinality;
Jonathan Hart3cfce8e2015-01-14 16:43:27 -080025import org.onlab.packet.Ethernet;
Thomas Vachuska6519e6f2015-03-11 02:29:31 -070026import org.onosproject.cfg.ComponentConfigService;
Brian O'Connorabafb502014-12-02 22:26:20 -080027import org.onosproject.core.ApplicationId;
28import org.onosproject.core.CoreService;
Jonathan Hart3cfce8e2015-01-14 16:43:27 -080029import org.onosproject.net.flow.DefaultTrafficSelector;
30import org.onosproject.net.flow.TrafficSelector;
Ayaka Koshibebfbe1d72015-03-16 16:51:41 -070031import org.onosproject.net.packet.InboundPacket;
Brian O'Connorabafb502014-12-02 22:26:20 -080032import org.onosproject.net.packet.PacketContext;
33import org.onosproject.net.packet.PacketProcessor;
34import org.onosproject.net.packet.PacketService;
35import org.onosproject.net.proxyarp.ProxyArpService;
Pavlin Radoslavov93b606b2015-02-25 17:28:39 -080036import org.osgi.service.component.ComponentContext;
alshabibc274c902014-10-03 14:58:27 -070037import org.slf4j.Logger;
38
Thomas Vachuska6519e6f2015-03-11 02:29:31 -070039import java.util.Dictionary;
40
Pavlin Radoslavov93b606b2015-02-25 17:28:39 -080041import static com.google.common.base.Strings.isNullOrEmpty;
Aaron Kruglikov07a923d2015-07-03 13:30:57 -070042import static org.onlab.packet.Ethernet.TYPE_ARP;
43import static org.onlab.packet.Ethernet.TYPE_IPV6;
44import static org.onlab.packet.ICMP6.NEIGHBOR_ADVERTISEMENT;
45import static org.onlab.packet.ICMP6.NEIGHBOR_SOLICITATION;
46import static org.onlab.packet.IPv6.PROTOCOL_ICMP6;
47import static org.onosproject.net.packet.PacketPriority.CONTROL;
alshabib78baaf22015-02-18 18:55:45 -080048import static org.slf4j.LoggerFactory.getLogger;
49
alshabibc274c902014-10-03 14:58:27 -070050/**
51 * Sample reactive proxy arp application.
52 */
53@Component(immediate = true)
54public class ProxyArp {
55
alshabibc274c902014-10-03 14:58:27 -070056 private final Logger log = getLogger(getClass());
57
58 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
59 protected PacketService packetService;
60
61 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
62 protected ProxyArpService proxyArpService;
63
64 private ProxyArpProcessor processor = new ProxyArpProcessor();
65
alshabib92c65ad2014-10-08 21:56:05 -070066 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
67 protected CoreService coreService;
68
Thomas Vachuska6519e6f2015-03-11 02:29:31 -070069 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
70 protected ComponentConfigService cfgService;
71
alshabibc274c902014-10-03 14:58:27 -070072 private ApplicationId appId;
73
Pavlin Radoslavov93b606b2015-02-25 17:28:39 -080074 @Property(name = "ipv6NeighborDiscovery", boolValue = false,
Thomas Vachuska6519e6f2015-03-11 02:29:31 -070075 label = "Enable IPv6 Neighbor Discovery; default is false")
Ayaka Koshibebfbe1d72015-03-16 16:51:41 -070076 protected boolean ipv6NeighborDiscovery = false;
Pavlin Radoslavov93b606b2015-02-25 17:28:39 -080077
alshabibc274c902014-10-03 14:58:27 -070078 @Activate
Pavlin Radoslavov93b606b2015-02-25 17:28:39 -080079 public void activate(ComponentContext context) {
Thomas Vachuska6519e6f2015-03-11 02:29:31 -070080 cfgService.registerProperties(getClass());
Brian O'Connorabafb502014-12-02 22:26:20 -080081 appId = coreService.registerApplication("org.onosproject.proxyarp");
Pavlin Radoslavov93b606b2015-02-25 17:28:39 -080082
Brian O'Connor3b783262015-07-29 17:49:24 -070083 packetService.addProcessor(processor, PacketProcessor.director(1));
Charles M.C. Chane148de82015-05-06 12:38:21 +080084 readComponentConfiguration(context);
Jonathan Hart39ee6482015-08-31 16:00:19 +020085 requestPackets();
Jonathan Hart3cfce8e2015-01-14 16:43:27 -080086
Charles M.C. Chane148de82015-05-06 12:38:21 +080087 log.info("Started with Application ID {}", appId.id());
88 }
89
90 @Deactivate
91 public void deactivate() {
Charles M.C. Chane148de82015-05-06 12:38:21 +080092 cfgService.unregisterProperties(getClass(), false);
Aaron Kruglikov07a923d2015-07-03 13:30:57 -070093 withdrawIntercepts();
Charles M.C. Chane148de82015-05-06 12:38:21 +080094 packetService.removeProcessor(processor);
95 processor = null;
96 log.info("Stopped");
97 }
98
99 @Modified
100 public void modified(ComponentContext context) {
Charles M.C. Chane148de82015-05-06 12:38:21 +0800101 readComponentConfiguration(context);
Jonathan Hart39ee6482015-08-31 16:00:19 +0200102 requestPackets();
Charles M.C. Chane148de82015-05-06 12:38:21 +0800103 }
104
105 /**
106 * Request packet in via PacketService.
107 */
Jonathan Hart39ee6482015-08-31 16:00:19 +0200108 private void requestPackets() {
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800109 TrafficSelector.Builder selectorBuilder =
110 DefaultTrafficSelector.builder();
Aaron Kruglikov07a923d2015-07-03 13:30:57 -0700111 selectorBuilder.matchEthType(TYPE_ARP);
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800112 packetService.requestPackets(selectorBuilder.build(),
Aaron Kruglikov07a923d2015-07-03 13:30:57 -0700113 CONTROL, appId);
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800114
Aaron Kruglikov07a923d2015-07-03 13:30:57 -0700115 selectorBuilder = DefaultTrafficSelector.builder();
116 selectorBuilder.matchEthType(TYPE_IPV6);
117 selectorBuilder.matchIPProtocol(PROTOCOL_ICMP6);
118 selectorBuilder.matchIcmpv6Type(NEIGHBOR_SOLICITATION);
Pavlin Radoslavov93b606b2015-02-25 17:28:39 -0800119 if (ipv6NeighborDiscovery) {
120 // IPv6 Neighbor Solicitation packet.
Pavlin Radoslavov93b606b2015-02-25 17:28:39 -0800121 packetService.requestPackets(selectorBuilder.build(),
Aaron Kruglikov07a923d2015-07-03 13:30:57 -0700122 CONTROL, appId);
123 } else {
124 packetService.cancelPackets(selectorBuilder.build(),
125 CONTROL, appId);
Pavlin Radoslavov93b606b2015-02-25 17:28:39 -0800126 }
Aaron Kruglikov07a923d2015-07-03 13:30:57 -0700127
128 // IPv6 Neighbor Advertisement packet.
129 selectorBuilder = DefaultTrafficSelector.builder();
130 selectorBuilder.matchEthType(TYPE_IPV6);
131 selectorBuilder.matchIPProtocol(PROTOCOL_ICMP6);
132 selectorBuilder.matchIcmpv6Type(NEIGHBOR_ADVERTISEMENT);
133 if (ipv6NeighborDiscovery) {
134 packetService.requestPackets(selectorBuilder.build(),
135 CONTROL, appId);
136 } else {
137 packetService.cancelPackets(selectorBuilder.build(),
138 CONTROL, appId);
139 }
140
141
142 }
143
144 /**
145 * Cancel requested packet in via packet service.
146 */
147 private void withdrawIntercepts() {
148 TrafficSelector.Builder selectorBuilder =
149 DefaultTrafficSelector.builder();
150 selectorBuilder.matchEthType(TYPE_ARP);
151 packetService.cancelPackets(selectorBuilder.build(), CONTROL, appId);
152 selectorBuilder = DefaultTrafficSelector.builder();
153 selectorBuilder.matchEthType(TYPE_IPV6);
154 selectorBuilder.matchIPProtocol(PROTOCOL_ICMP6);
155 selectorBuilder.matchIcmpv6Type(NEIGHBOR_SOLICITATION);
156 packetService.cancelPackets(selectorBuilder.build(), CONTROL, appId);
157 selectorBuilder = DefaultTrafficSelector.builder();
158 selectorBuilder.matchEthType(TYPE_IPV6);
159 selectorBuilder.matchIPProtocol(PROTOCOL_ICMP6);
160 selectorBuilder.matchIcmpv6Type(NEIGHBOR_ADVERTISEMENT);
161 packetService.cancelPackets(selectorBuilder.build(), CONTROL, appId);
162
Pavlin Radoslavov93b606b2015-02-25 17:28:39 -0800163 }
164
165 /**
166 * Extracts properties from the component configuration context.
167 *
168 * @param context the component context
169 */
170 private void readComponentConfiguration(ComponentContext context) {
171 Dictionary<?, ?> properties = context.getProperties();
172 Boolean flag;
173
174 flag = isPropertyEnabled(properties, "ipv6NeighborDiscovery");
175 if (flag == null) {
176 log.info("IPv6 Neighbor Discovery is not configured, " +
Thomas Vachuska6519e6f2015-03-11 02:29:31 -0700177 "using current value of {}", ipv6NeighborDiscovery);
Pavlin Radoslavov93b606b2015-02-25 17:28:39 -0800178 } else {
179 ipv6NeighborDiscovery = flag;
180 log.info("Configured. IPv6 Neighbor Discovery is {}",
181 ipv6NeighborDiscovery ? "enabled" : "disabled");
182 }
183 }
184
185 /**
186 * Check property name is defined and set to true.
187 *
Thomas Vachuska6519e6f2015-03-11 02:29:31 -0700188 * @param properties properties to be looked up
Pavlin Radoslavov93b606b2015-02-25 17:28:39 -0800189 * @param propertyName the name of the property to look up
190 * @return value when the propertyName is defined or return null
191 */
192 private static Boolean isPropertyEnabled(Dictionary<?, ?> properties,
193 String propertyName) {
194 Boolean value = null;
195 try {
196 String s = (String) properties.get(propertyName);
197 value = isNullOrEmpty(s) ? null : s.trim().equals("true");
198 } catch (ClassCastException e) {
199 // No propertyName defined.
200 value = null;
201 }
202 return value;
203 }
alshabibc274c902014-10-03 14:58:27 -0700204
205 /**
206 * Packet processor responsible for forwarding packets along their paths.
207 */
208 private class ProxyArpProcessor implements PacketProcessor {
209
210 @Override
211 public void process(PacketContext context) {
212 // Stop processing if the packet has been handled, since we
213 // can't do any more to it.
214 if (context.isHandled()) {
215 return;
216 }
Ayaka Koshibebfbe1d72015-03-16 16:51:41 -0700217 // If IPv6 NDP is disabled, don't handle IPv6 frames.
218 InboundPacket pkt = context.inPacket();
219 Ethernet ethPkt = pkt.parsed();
220 if (ethPkt == null) {
221 return;
222 }
Aaron Kruglikov07a923d2015-07-03 13:30:57 -0700223 if (!ipv6NeighborDiscovery && (ethPkt.getEtherType() == TYPE_IPV6)) {
Ayaka Koshibebfbe1d72015-03-16 16:51:41 -0700224 return;
225 }
Rusty Eddy29acad62015-07-07 19:33:47 -0700226
227 // Do not ARP for multicast packets. Let mfwd handle them.
228 if (ethPkt.getEtherType() == Ethernet.TYPE_IPV4) {
229 if (ethPkt.getDestinationMAC().isMulticast()) {
230 return;
231 }
232 }
233
alshabibc274c902014-10-03 14:58:27 -0700234 //handle the arp packet.
Kunihiro Ishigurof1bff502015-01-30 15:47:06 -0800235 proxyArpService.handlePacket(context);
alshabibc274c902014-10-03 14:58:27 -0700236 }
237 }
238}
239
240