blob: 2eb1d5ecfbc33337b0ae17916871fe610ea08548 [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;
Brian O'Connorbc865f62015-10-08 21:39:53 -070026import org.onlab.packet.ICMP6;
27import org.onlab.packet.IPv6;
Thomas Vachuska6519e6f2015-03-11 02:29:31 -070028import org.onosproject.cfg.ComponentConfigService;
Brian O'Connorabafb502014-12-02 22:26:20 -080029import org.onosproject.core.ApplicationId;
30import org.onosproject.core.CoreService;
Jonathan Hart3cfce8e2015-01-14 16:43:27 -080031import org.onosproject.net.flow.DefaultTrafficSelector;
32import org.onosproject.net.flow.TrafficSelector;
Ayaka Koshibebfbe1d72015-03-16 16:51:41 -070033import org.onosproject.net.packet.InboundPacket;
Brian O'Connorabafb502014-12-02 22:26:20 -080034import org.onosproject.net.packet.PacketContext;
35import org.onosproject.net.packet.PacketProcessor;
36import org.onosproject.net.packet.PacketService;
37import org.onosproject.net.proxyarp.ProxyArpService;
Pavlin Radoslavov93b606b2015-02-25 17:28:39 -080038import org.osgi.service.component.ComponentContext;
alshabibc274c902014-10-03 14:58:27 -070039import org.slf4j.Logger;
40
Thomas Vachuska6519e6f2015-03-11 02:29:31 -070041import java.util.Dictionary;
42
Pavlin Radoslavov93b606b2015-02-25 17:28:39 -080043import static com.google.common.base.Strings.isNullOrEmpty;
Aaron Kruglikov07a923d2015-07-03 13:30:57 -070044import static org.onlab.packet.Ethernet.TYPE_ARP;
45import static org.onlab.packet.Ethernet.TYPE_IPV6;
46import static org.onlab.packet.ICMP6.NEIGHBOR_ADVERTISEMENT;
47import static org.onlab.packet.ICMP6.NEIGHBOR_SOLICITATION;
48import static org.onlab.packet.IPv6.PROTOCOL_ICMP6;
49import static org.onosproject.net.packet.PacketPriority.CONTROL;
alshabib78baaf22015-02-18 18:55:45 -080050import static org.slf4j.LoggerFactory.getLogger;
51
alshabibc274c902014-10-03 14:58:27 -070052/**
53 * Sample reactive proxy arp application.
54 */
55@Component(immediate = true)
56public class ProxyArp {
57
alshabibc274c902014-10-03 14:58:27 -070058 private final Logger log = getLogger(getClass());
59
60 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
61 protected PacketService packetService;
62
63 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
64 protected ProxyArpService proxyArpService;
65
66 private ProxyArpProcessor processor = new ProxyArpProcessor();
67
alshabib92c65ad2014-10-08 21:56:05 -070068 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
69 protected CoreService coreService;
70
Thomas Vachuska6519e6f2015-03-11 02:29:31 -070071 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
72 protected ComponentConfigService cfgService;
73
alshabibc274c902014-10-03 14:58:27 -070074 private ApplicationId appId;
75
Pavlin Radoslavov93b606b2015-02-25 17:28:39 -080076 @Property(name = "ipv6NeighborDiscovery", boolValue = false,
Thomas Vachuska6519e6f2015-03-11 02:29:31 -070077 label = "Enable IPv6 Neighbor Discovery; default is false")
Ayaka Koshibebfbe1d72015-03-16 16:51:41 -070078 protected boolean ipv6NeighborDiscovery = false;
Pavlin Radoslavov93b606b2015-02-25 17:28:39 -080079
alshabibc274c902014-10-03 14:58:27 -070080 @Activate
Pavlin Radoslavov93b606b2015-02-25 17:28:39 -080081 public void activate(ComponentContext context) {
Thomas Vachuska6519e6f2015-03-11 02:29:31 -070082 cfgService.registerProperties(getClass());
Brian O'Connorabafb502014-12-02 22:26:20 -080083 appId = coreService.registerApplication("org.onosproject.proxyarp");
Pavlin Radoslavov93b606b2015-02-25 17:28:39 -080084
Brian O'Connor3b783262015-07-29 17:49:24 -070085 packetService.addProcessor(processor, PacketProcessor.director(1));
Charles M.C. Chane148de82015-05-06 12:38:21 +080086 readComponentConfiguration(context);
Jonathan Hart39ee6482015-08-31 16:00:19 +020087 requestPackets();
Jonathan Hart3cfce8e2015-01-14 16:43:27 -080088
Charles M.C. Chane148de82015-05-06 12:38:21 +080089 log.info("Started with Application ID {}", appId.id());
90 }
91
92 @Deactivate
93 public void deactivate() {
Charles M.C. Chane148de82015-05-06 12:38:21 +080094 cfgService.unregisterProperties(getClass(), false);
Aaron Kruglikov07a923d2015-07-03 13:30:57 -070095 withdrawIntercepts();
Charles M.C. Chane148de82015-05-06 12:38:21 +080096 packetService.removeProcessor(processor);
97 processor = null;
98 log.info("Stopped");
99 }
100
101 @Modified
102 public void modified(ComponentContext context) {
Charles M.C. Chane148de82015-05-06 12:38:21 +0800103 readComponentConfiguration(context);
Jonathan Hart39ee6482015-08-31 16:00:19 +0200104 requestPackets();
Charles M.C. Chane148de82015-05-06 12:38:21 +0800105 }
106
107 /**
108 * Request packet in via PacketService.
109 */
Jonathan Hart39ee6482015-08-31 16:00:19 +0200110 private void requestPackets() {
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800111 TrafficSelector.Builder selectorBuilder =
112 DefaultTrafficSelector.builder();
Aaron Kruglikov07a923d2015-07-03 13:30:57 -0700113 selectorBuilder.matchEthType(TYPE_ARP);
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800114 packetService.requestPackets(selectorBuilder.build(),
Aaron Kruglikov07a923d2015-07-03 13:30:57 -0700115 CONTROL, appId);
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800116
Aaron Kruglikov07a923d2015-07-03 13:30:57 -0700117 selectorBuilder = DefaultTrafficSelector.builder();
118 selectorBuilder.matchEthType(TYPE_IPV6);
119 selectorBuilder.matchIPProtocol(PROTOCOL_ICMP6);
120 selectorBuilder.matchIcmpv6Type(NEIGHBOR_SOLICITATION);
Pavlin Radoslavov93b606b2015-02-25 17:28:39 -0800121 if (ipv6NeighborDiscovery) {
122 // IPv6 Neighbor Solicitation packet.
Pavlin Radoslavov93b606b2015-02-25 17:28:39 -0800123 packetService.requestPackets(selectorBuilder.build(),
Aaron Kruglikov07a923d2015-07-03 13:30:57 -0700124 CONTROL, appId);
125 } else {
126 packetService.cancelPackets(selectorBuilder.build(),
127 CONTROL, appId);
Pavlin Radoslavov93b606b2015-02-25 17:28:39 -0800128 }
Aaron Kruglikov07a923d2015-07-03 13:30:57 -0700129
130 // IPv6 Neighbor Advertisement packet.
131 selectorBuilder = DefaultTrafficSelector.builder();
132 selectorBuilder.matchEthType(TYPE_IPV6);
133 selectorBuilder.matchIPProtocol(PROTOCOL_ICMP6);
134 selectorBuilder.matchIcmpv6Type(NEIGHBOR_ADVERTISEMENT);
135 if (ipv6NeighborDiscovery) {
136 packetService.requestPackets(selectorBuilder.build(),
137 CONTROL, appId);
138 } else {
139 packetService.cancelPackets(selectorBuilder.build(),
140 CONTROL, appId);
141 }
142
143
144 }
145
146 /**
147 * Cancel requested packet in via packet service.
148 */
149 private void withdrawIntercepts() {
150 TrafficSelector.Builder selectorBuilder =
151 DefaultTrafficSelector.builder();
152 selectorBuilder.matchEthType(TYPE_ARP);
153 packetService.cancelPackets(selectorBuilder.build(), CONTROL, appId);
154 selectorBuilder = DefaultTrafficSelector.builder();
155 selectorBuilder.matchEthType(TYPE_IPV6);
156 selectorBuilder.matchIPProtocol(PROTOCOL_ICMP6);
157 selectorBuilder.matchIcmpv6Type(NEIGHBOR_SOLICITATION);
158 packetService.cancelPackets(selectorBuilder.build(), CONTROL, appId);
159 selectorBuilder = DefaultTrafficSelector.builder();
160 selectorBuilder.matchEthType(TYPE_IPV6);
161 selectorBuilder.matchIPProtocol(PROTOCOL_ICMP6);
162 selectorBuilder.matchIcmpv6Type(NEIGHBOR_ADVERTISEMENT);
163 packetService.cancelPackets(selectorBuilder.build(), CONTROL, appId);
164
Pavlin Radoslavov93b606b2015-02-25 17:28:39 -0800165 }
166
167 /**
168 * Extracts properties from the component configuration context.
169 *
170 * @param context the component context
171 */
172 private void readComponentConfiguration(ComponentContext context) {
173 Dictionary<?, ?> properties = context.getProperties();
174 Boolean flag;
175
176 flag = isPropertyEnabled(properties, "ipv6NeighborDiscovery");
177 if (flag == null) {
178 log.info("IPv6 Neighbor Discovery is not configured, " +
Thomas Vachuska6519e6f2015-03-11 02:29:31 -0700179 "using current value of {}", ipv6NeighborDiscovery);
Pavlin Radoslavov93b606b2015-02-25 17:28:39 -0800180 } else {
181 ipv6NeighborDiscovery = flag;
182 log.info("Configured. IPv6 Neighbor Discovery is {}",
183 ipv6NeighborDiscovery ? "enabled" : "disabled");
184 }
185 }
186
187 /**
188 * Check property name is defined and set to true.
189 *
Thomas Vachuska6519e6f2015-03-11 02:29:31 -0700190 * @param properties properties to be looked up
Pavlin Radoslavov93b606b2015-02-25 17:28:39 -0800191 * @param propertyName the name of the property to look up
192 * @return value when the propertyName is defined or return null
193 */
194 private static Boolean isPropertyEnabled(Dictionary<?, ?> properties,
195 String propertyName) {
196 Boolean value = null;
197 try {
198 String s = (String) properties.get(propertyName);
199 value = isNullOrEmpty(s) ? null : s.trim().equals("true");
200 } catch (ClassCastException e) {
201 // No propertyName defined.
202 value = null;
203 }
204 return value;
205 }
alshabibc274c902014-10-03 14:58:27 -0700206
207 /**
208 * Packet processor responsible for forwarding packets along their paths.
209 */
210 private class ProxyArpProcessor implements PacketProcessor {
211
212 @Override
213 public void process(PacketContext context) {
214 // Stop processing if the packet has been handled, since we
215 // can't do any more to it.
216 if (context.isHandled()) {
217 return;
218 }
Brian O'Connorbc865f62015-10-08 21:39:53 -0700219
Ayaka Koshibebfbe1d72015-03-16 16:51:41 -0700220 InboundPacket pkt = context.inPacket();
221 Ethernet ethPkt = pkt.parsed();
222 if (ethPkt == null) {
223 return;
224 }
Brian O'Connorbc865f62015-10-08 21:39:53 -0700225
226 if (ethPkt.getEtherType() == TYPE_ARP) {
227 //handle the arp packet.
228 proxyArpService.handlePacket(context);
229 } else if (ipv6NeighborDiscovery && ethPkt.getEtherType() == TYPE_IPV6) {
230 IPv6 ipv6Pkt = (IPv6) ethPkt.getPayload();
231 if (ipv6Pkt.getNextHeader() == IPv6.PROTOCOL_ICMP6) {
232 ICMP6 icmp6Pkt = (ICMP6) ipv6Pkt.getPayload();
233 if (icmp6Pkt.getIcmpType() == NEIGHBOR_SOLICITATION ||
234 icmp6Pkt.getIcmpType() == NEIGHBOR_ADVERTISEMENT) {
235 // handle ICMPv6 solicitations and advertisements
236 proxyArpService.handlePacket(context);
237 }
238 }
Ayaka Koshibebfbe1d72015-03-16 16:51:41 -0700239 }
Rusty Eddy29acad62015-07-07 19:33:47 -0700240
Brian O'Connorbc865f62015-10-08 21:39:53 -0700241 // FIXME why were we listening to IPv4 frames at all?
Rusty Eddy29acad62015-07-07 19:33:47 -0700242 // Do not ARP for multicast packets. Let mfwd handle them.
243 if (ethPkt.getEtherType() == Ethernet.TYPE_IPV4) {
244 if (ethPkt.getDestinationMAC().isMulticast()) {
245 return;
246 }
247 }
alshabibc274c902014-10-03 14:58:27 -0700248 }
249 }
250}