blob: 350e67c38510b99f4de163ce135e003c7ca934f7 [file] [log] [blame]
Jonathan Hart9bdaaec2016-08-22 13:33:45 -07001/*
2 * Copyright 2016-present Open Networking Laboratory
3 *
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 */
16
17package org.onosproject.incubator.net.neighbour.impl;
18
19import com.google.common.annotations.Beta;
20import org.onlab.packet.ARP;
21import org.onlab.packet.Ethernet;
22import org.onlab.packet.ICMP6;
23import org.onlab.packet.IPv6;
24import org.onlab.packet.Ip4Address;
25import org.onlab.packet.Ip6Address;
26import org.onlab.packet.IpAddress;
27import org.onlab.packet.MacAddress;
28import org.onlab.packet.VlanId;
29import org.onlab.packet.ndp.NeighborSolicitation;
30import org.onosproject.incubator.net.intf.Interface;
31import org.onosproject.incubator.net.neighbour.NeighbourMessageActions;
32import org.onosproject.incubator.net.neighbour.NeighbourMessageContext;
33import org.onosproject.incubator.net.neighbour.NeighbourMessageType;
34import org.onosproject.incubator.net.neighbour.NeighbourProtocol;
35import org.onosproject.net.ConnectPoint;
36
Jonathan Hart584ea2d2016-10-11 10:49:16 +020037import java.util.Objects;
38
Jonathan Hart9bdaaec2016-08-22 13:33:45 -070039import static com.google.common.base.Preconditions.checkState;
40
41/**
42 * Default implementation of a neighbour message context.
43 */
44@Beta
45public class DefaultNeighbourMessageContext implements NeighbourMessageContext {
46
47 private final NeighbourProtocol protocol;
48 private final NeighbourMessageType type;
49
50 private final IpAddress target;
51 private final IpAddress sender;
52
53 private final Ethernet eth;
54 private final ConnectPoint inPort;
55
56 private final NeighbourMessageActions actions;
57
58 /**
59 * Creates a new neighbour message context.
60 *
61 * @param actions actions
62 * @param eth ethernet frame
63 * @param inPort incoming port
64 * @param protocol message protocol
65 * @param type message type
66 * @param target target IP address
67 * @param sender sender IP address
68 */
69 DefaultNeighbourMessageContext(NeighbourMessageActions actions,
70 Ethernet eth, ConnectPoint inPort,
71 NeighbourProtocol protocol,
72 NeighbourMessageType type,
73 IpAddress target, IpAddress sender) {
74 this.actions = actions;
75 this.eth = eth;
76 this.inPort = inPort;
77 this.protocol = protocol;
78 this.type = type;
79 this.target = target;
80 this.sender = sender;
81 }
82
83 @Override
84 public ConnectPoint inPort() {
85 return inPort;
86 }
87
88 @Override
89 public Ethernet packet() {
90 return eth;
91 }
92
93 @Override
94 public NeighbourProtocol protocol() {
95 return protocol;
96 }
97
98 @Override
99 public NeighbourMessageType type() {
100 return type;
101 }
102
103 @Override
104 public VlanId vlan() {
105 return VlanId.vlanId(eth.getVlanID());
106 }
107
108 @Override
109 public MacAddress srcMac() {
Jonathan Hartc4f681c2016-09-09 07:14:25 -0700110 return eth.getSourceMAC();
111 }
112
113 @Override
114 public MacAddress dstMac() {
115 return eth.getDestinationMAC();
Jonathan Hart9bdaaec2016-08-22 13:33:45 -0700116 }
117
118 @Override
119 public IpAddress target() {
120 return target;
121 }
122
123 @Override
124 public IpAddress sender() {
125 return sender;
126 }
127
128 @Override
Jonathan Hart2efe0c22016-09-21 12:04:45 -0700129 public void forward(ConnectPoint outPort) {
Jonathan Hart1e393bb2016-09-14 08:51:09 -0700130 actions.forward(this, outPort);
Jonathan Hart9bdaaec2016-08-22 13:33:45 -0700131 }
132
133 @Override
Jonathan Hart2efe0c22016-09-21 12:04:45 -0700134 public void forward(Interface outIntf) {
Jonathan Hart1e393bb2016-09-14 08:51:09 -0700135 actions.forward(this, outIntf);
Jonathan Hart9bdaaec2016-08-22 13:33:45 -0700136 }
137
138 @Override
139 public void reply(MacAddress targetMac) {
140 checkState(type == NeighbourMessageType.REQUEST, "can only reply to requests");
141
142 actions.reply(this, targetMac);
143 }
144
145 @Override
146 public void flood() {
147 actions.flood(this);
148 }
149
150 @Override
151 public void drop() {
152 actions.drop(this);
153 }
154
Jonathan Hart584ea2d2016-10-11 10:49:16 +0200155 @Override
156 public int hashCode() {
157 return Objects.hash(protocol, type, target, sender, eth, inPort);
158 }
159
160 @Override
161 public boolean equals(Object obj) {
162 if (!(obj instanceof DefaultNeighbourMessageContext)) {
163 return false;
164 }
165
166 DefaultNeighbourMessageContext that = (DefaultNeighbourMessageContext) obj;
167
168 return Objects.equals(protocol, that.protocol) &&
169 Objects.equals(type, that.type) &&
170 Objects.equals(target, that.target) &&
171 Objects.equals(sender, that.sender) &&
172 Objects.equals(eth, that.eth) &&
173 Objects.equals(inPort, that.inPort);
174 }
175
Jonathan Hart9bdaaec2016-08-22 13:33:45 -0700176 /**
177 * Attempts to create a MessageContext for the given Ethernet frame. If the
178 * frame is a valid ARP or NDP request or response, a context will be
179 * created.
180 *
181 * @param eth input Ethernet frame
182 * @param inPort in port
Ray Milkeyef794342016-11-09 16:20:29 -0800183 * @param actions actions to take
Jonathan Hart9bdaaec2016-08-22 13:33:45 -0700184 * @return MessageContext if the packet was ARP or NDP, otherwise null
185 */
186 public static NeighbourMessageContext createContext(Ethernet eth,
187 ConnectPoint inPort,
188 NeighbourMessageActions actions) {
189 if (eth.getEtherType() == Ethernet.TYPE_ARP) {
190 return createArpContext(eth, inPort, actions);
191 } else if (eth.getEtherType() == Ethernet.TYPE_IPV6) {
192 return createNdpContext(eth, inPort, actions);
193 }
194
195 return null;
196 }
197
198 /**
199 * Extracts context information from ARP packets.
200 *
201 * @param eth input Ethernet frame that is thought to be ARP
202 * @param inPort in port
Ray Milkeyef794342016-11-09 16:20:29 -0800203 * @param actions actions to take
Jonathan Hart9bdaaec2016-08-22 13:33:45 -0700204 * @return MessageContext object if the packet was a valid ARP packet,
205 * otherwise null
206 */
207 private static NeighbourMessageContext createArpContext(Ethernet eth,
208 ConnectPoint inPort,
209 NeighbourMessageActions actions) {
210 if (eth.getEtherType() != Ethernet.TYPE_ARP) {
211 return null;
212 }
213
214 ARP arp = (ARP) eth.getPayload();
215
216 IpAddress target = Ip4Address.valueOf(arp.getTargetProtocolAddress());
217 IpAddress sender = Ip4Address.valueOf(arp.getSenderProtocolAddress());
218
219 NeighbourMessageType type;
220 if (arp.getOpCode() == ARP.OP_REQUEST) {
221 type = NeighbourMessageType.REQUEST;
222 } else if (arp.getOpCode() == ARP.OP_REPLY) {
223 type = NeighbourMessageType.REPLY;
224 } else {
225 return null;
226 }
227
228 return new DefaultNeighbourMessageContext(actions, eth, inPort,
229 NeighbourProtocol.ARP, type, target, sender);
230 }
231
232 /**
233 * Extracts context information from NDP packets.
234 *
235 * @param eth input Ethernet frame that is thought to be NDP
236 * @param inPort in port
Ray Milkeyef794342016-11-09 16:20:29 -0800237 * @param actions actions to take
Jonathan Hart9bdaaec2016-08-22 13:33:45 -0700238 * @return MessageContext object if the packet was a valid NDP packet,
239 * otherwise null
240 */
241 private static NeighbourMessageContext createNdpContext(Ethernet eth,
242 ConnectPoint inPort,
243 NeighbourMessageActions actions) {
244 if (eth.getEtherType() != Ethernet.TYPE_IPV6) {
245 return null;
246 }
247 IPv6 ipv6 = (IPv6) eth.getPayload();
248
249 if (ipv6.getNextHeader() != IPv6.PROTOCOL_ICMP6) {
250 return null;
251 }
252 ICMP6 icmpv6 = (ICMP6) ipv6.getPayload();
253
254 IpAddress sender = Ip6Address.valueOf(ipv6.getSourceAddress());
255 IpAddress target = null;
256
257 NeighbourMessageType type;
258 if (icmpv6.getIcmpType() == ICMP6.NEIGHBOR_SOLICITATION) {
259 type = NeighbourMessageType.REQUEST;
260 NeighborSolicitation nsol = (NeighborSolicitation) icmpv6.getPayload();
261 target = Ip6Address.valueOf(nsol.getTargetAddress());
262 } else if (icmpv6.getIcmpType() == ICMP6.NEIGHBOR_ADVERTISEMENT) {
263 type = NeighbourMessageType.REPLY;
264 } else {
265 return null;
266 }
267
268 return new DefaultNeighbourMessageContext(actions, eth, inPort,
269 NeighbourProtocol.NDP, type, target, sender);
270 }
271
272}