blob: ed78212a7969bf57a0269f47ab1475b89db47a49 [file] [log] [blame]
Jonathan Hart584ea2d2016-10-11 10:49:16 +02001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Jonathan Hart584ea2d2016-10-11 10:49:16 +02003 *
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
Ray Milkeyb65d7842017-08-03 16:28:24 -070017package org.onosproject.net.neighbour.impl;
Jonathan Hart584ea2d2016-10-11 10:49:16 +020018
19import org.onlab.packet.ARP;
20import org.onlab.packet.Ethernet;
21import org.onlab.packet.ICMP6;
22import org.onlab.packet.IPv6;
23import org.onlab.packet.Ip4Address;
24import org.onlab.packet.Ip6Address;
25import org.onlab.packet.MacAddress;
26import org.onlab.packet.VlanId;
27import org.onlab.packet.ndp.NeighborAdvertisement;
28import org.onlab.packet.ndp.NeighborDiscoveryOptions;
29import org.onlab.util.Tools;
Ray Milkeyfacf2862017-08-03 11:58:29 -070030import org.onosproject.net.intf.Interface;
Ray Milkeyb65d7842017-08-03 16:28:24 -070031import org.onosproject.net.neighbour.NeighbourMessageActions;
32import org.onosproject.net.neighbour.NeighbourMessageContext;
Jonathan Hart584ea2d2016-10-11 10:49:16 +020033import org.onosproject.net.ConnectPoint;
34import org.onosproject.net.edge.EdgePortService;
35import org.onosproject.net.flow.DefaultTrafficTreatment;
36import org.onosproject.net.flow.TrafficTreatment;
37import org.onosproject.net.packet.DefaultOutboundPacket;
38import org.onosproject.net.packet.PacketService;
39
40import java.nio.ByteBuffer;
41
42/**
43 * Implementation of neighbour message actions.
44 */
45public class DefaultNeighbourMessageActions implements NeighbourMessageActions {
46
47 private final EdgePortService edgeService;
48 private final PacketService packetService;
49
50 public DefaultNeighbourMessageActions(PacketService packetService,
51 EdgePortService edgeService) {
52 this.packetService = packetService;
53 this.edgeService = edgeService;
54 }
55
56 @Override
57 public void reply(NeighbourMessageContext context, MacAddress targetMac) {
58 replyInternal(context, targetMac);
59 }
60
61 @Override
62 public void forward(NeighbourMessageContext context, ConnectPoint outPort) {
63 sendTo(context.packet(), outPort);
64 }
65
66 @Override
67 public void forward(NeighbourMessageContext context, Interface outIntf) {
68 Ethernet packetOut = (Ethernet) context.packet().clone();
69 if (outIntf.vlan().equals(VlanId.NONE)) {
70 // The egress interface has no VLAN Id. Send out an untagged
71 // packet
72 packetOut.setVlanID(Ethernet.VLAN_UNTAGGED);
73 } else {
74 // The egress interface has a VLAN set. Send out a tagged packet
75 packetOut.setVlanID(outIntf.vlan().toShort());
76 }
77 sendTo(packetOut, outIntf.connectPoint());
78 }
79
80 @Override
81 public void flood(NeighbourMessageContext context) {
82 Tools.stream(edgeService.getEdgePoints())
83 .filter(cp -> !cp.equals(context.inPort()))
84 .forEach(cp -> sendTo(context.packet(), cp));
85 }
86
87 @Override
88 public void drop(NeighbourMessageContext context) {
89
90 }
91
92 private void replyInternal(NeighbourMessageContext context, MacAddress targetMac) {
93 switch (context.protocol()) {
94 case ARP:
95 sendTo(ARP.buildArpReply((Ip4Address) context.target(),
96 targetMac, context.packet()), context.inPort());
97 break;
98 case NDP:
99 sendTo(buildNdpReply((Ip6Address) context.target(), targetMac,
100 context.packet()), context.inPort());
101 break;
102 default:
103 break;
104 }
105 }
106
107 /**
108 * Outputs a packet out a specific port.
109 *
110 * @param packet the packet to send
111 * @param outPort the port to send it out
112 */
113 private void sendTo(Ethernet packet, ConnectPoint outPort) {
114 sendTo(ByteBuffer.wrap(packet.serialize()), outPort);
115 }
116
117 /**
118 * Outputs a packet out a specific port.
119 *
120 * @param packet packet to send
121 * @param outPort port to send it out
122 */
123 private void sendTo(ByteBuffer packet, ConnectPoint outPort) {
124 if (!edgeService.isEdgePoint(outPort)) {
125 // Sanity check to make sure we don't send the packet out an
126 // internal port and create a loop (could happen due to
127 // misconfiguration).
128 return;
129 }
130
131 TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder();
132 builder.setOutput(outPort.port());
133 packetService.emit(new DefaultOutboundPacket(outPort.deviceId(),
134 builder.build(), packet));
135 }
136
137 /**
138 * Builds an NDP reply based on a request.
139 *
140 * @param srcIp the IP address to use as the reply source
141 * @param srcMac the MAC address to use as the reply source
142 * @param request the Neighbor Solicitation request we got
143 * @return an Ethernet frame containing the Neighbor Advertisement reply
144 */
145 private Ethernet buildNdpReply(Ip6Address srcIp, MacAddress srcMac,
146 Ethernet request) {
147 Ethernet eth = new Ethernet();
148 eth.setDestinationMACAddress(request.getSourceMAC());
149 eth.setSourceMACAddress(srcMac);
150 eth.setEtherType(Ethernet.TYPE_IPV6);
151 eth.setVlanID(request.getVlanID());
152
153 IPv6 requestIp = (IPv6) request.getPayload();
154 IPv6 ipv6 = new IPv6();
155 ipv6.setSourceAddress(srcIp.toOctets());
156 ipv6.setDestinationAddress(requestIp.getSourceAddress());
157 ipv6.setHopLimit((byte) 255);
158
159 ICMP6 icmp6 = new ICMP6();
160 icmp6.setIcmpType(ICMP6.NEIGHBOR_ADVERTISEMENT);
161 icmp6.setIcmpCode((byte) 0);
162
163 NeighborAdvertisement nadv = new NeighborAdvertisement();
164 nadv.setTargetAddress(srcIp.toOctets());
165 nadv.setSolicitedFlag((byte) 1);
166 nadv.setOverrideFlag((byte) 1);
167 nadv.addOption(NeighborDiscoveryOptions.TYPE_TARGET_LL_ADDRESS,
168 srcMac.toBytes());
169
170 icmp6.setPayload(nadv);
171 ipv6.setPayload(icmp6);
172 eth.setPayload(ipv6);
173 return eth;
174 }
175}