blob: c1ad2cfef50a02eec1dcda805b321965f315aa4a [file] [log] [blame]
Rusty Eddy95421642015-10-21 17:22:13 -07001/*
2 * Copyright 2015 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 */
16package org.onosproject.pim.impl;
17
18import org.onlab.packet.Ethernet;
19import org.onlab.packet.IPv4;
20import org.onlab.packet.Ip4Address;
21import org.onlab.packet.IpAddress;
22import org.onlab.packet.IpPrefix;
23import org.onlab.packet.MacAddress;
24import org.onlab.packet.PIM;
25import org.onlab.packet.VlanId;
26import org.onosproject.core.ApplicationId;
27import org.onosproject.incubator.net.intf.Interface;
28import org.onosproject.net.ConnectPoint;
29import org.onosproject.net.flow.DefaultTrafficSelector;
30import org.onosproject.net.flow.DefaultTrafficTreatment;
31import org.onosproject.net.flow.TrafficSelector;
32import org.onosproject.net.flow.TrafficTreatment;
33import org.onosproject.net.packet.DefaultOutboundPacket;
34import org.onosproject.net.packet.InboundPacket;
35import org.onosproject.net.packet.OutboundPacket;
36import org.onosproject.net.packet.PacketContext;
37import org.onosproject.net.packet.PacketPriority;
38import org.onosproject.net.packet.PacketProcessor;
39import org.onosproject.net.packet.PacketService;
40import org.slf4j.Logger;
41
42import java.nio.ByteBuffer;
43
44import static com.google.common.base.Preconditions.checkNotNull;
45import static org.slf4j.LoggerFactory.getLogger;
46
47/**
48 * Handing Incoming and outgoing PIM packets.
49 */
50public final class PIMPacketHandler {
51 private final Logger log = getLogger(getClass());
52
53 private static PIMPacketHandler instance = null;
54
55 private PacketService packetService;
56 private PIMPacketProcessor processor = new PIMPacketProcessor();
57 private MacAddress pimDestinationMac = MacAddress.valueOf("01:00:5E:00:00:0d");
58
59 // Utility class
60 private PIMPacketHandler() {}
61
62 public static PIMPacketHandler getInstance() {
63 if (null == instance) {
64 instance = new PIMPacketHandler();
65 }
66 return instance;
67 }
68
69 /**
70 * Initialize the packet handling service.
71 *
72 * @param ps the packetService
73 * @param appId our application ID
74 */
75 public void initialize(PacketService ps, ApplicationId appId) {
76 packetService = ps;
77
78 // Build a traffic selector for all multicast traffic
79 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
80 selector.matchEthType(Ethernet.TYPE_IPV4);
81 selector.matchIPProtocol(IPv4.PROTOCOL_PIM);
82 packetService.requestPackets(selector.build(), PacketPriority.REACTIVE, appId);
83
84 packetService.addProcessor(processor, PacketProcessor.director(1));
85 }
86
87 /**
88 * Shutdown the packet handling service.
89 */
90 public void stop() {
91 packetService.removeProcessor(processor);
92 processor = null;
93 }
94
95 /**
96 * Packet processor responsible for handling IGMP packets.
97 */
98 public class PIMPacketProcessor implements PacketProcessor {
99 private final Logger log = getLogger(getClass());
100
101 @Override
102 public void process(PacketContext context) {
103 // Stop processing if the packet has been handled, since we
104 // can't do any more to it.
105 if (context.isHandled()) {
106 return;
107 }
108
109 InboundPacket pkt = context.inPacket();
110 if (pkt == null) {
111 return;
112 }
113
114 Ethernet ethPkt = pkt.parsed();
115 if (ethPkt == null) {
116 return;
117 }
118
119 /*
120 * IPv6 MLD packets are handled by ICMP6. We'll only deal
121 * with IPv4.
122 */
123 if (ethPkt.getEtherType() != Ethernet.TYPE_IPV4) {
124 return;
125 }
126
127 IPv4 ip = (IPv4) ethPkt.getPayload();
128 IpAddress gaddr = IpAddress.valueOf(ip.getDestinationAddress());
129 IpAddress saddr = Ip4Address.valueOf(ip.getSourceAddress());
130 log.debug("Packet (" + saddr.toString() + ", " + gaddr.toString() +
131 "\tingress port: " + context.inPacket().receivedFrom().toString());
132
133 if (ip.getProtocol() != IPv4.PROTOCOL_PIM) {
134 log.debug("PIM Picked up a non PIM packet: IP protocol: " + ip.getProtocol());
135 return;
136 }
137
138 // TODO: check incoming to be PIM.PIM_ADDRESS or "Our" address.
139 IpPrefix spfx = IpPrefix.valueOf(saddr, 32);
140 IpPrefix gpfx = IpPrefix.valueOf(gaddr, 32);
141
142 PIM pim = (PIM) ip.getPayload();
143 switch (pim.getPimMsgType()) {
144
145 case PIM.TYPE_HELLO:
146 processHello(ethPkt, context.inPacket().receivedFrom());
147 break;
148
149 case PIM.TYPE_JOIN_PRUNE_REQUEST:
150 // Create the function
151 break;
152
153 case PIM.TYPE_ASSERT:
154 case PIM.TYPE_BOOTSTRAP:
155 case PIM.TYPE_CANDIDATE_RP_ADV:
156 case PIM.TYPE_GRAFT:
157 case PIM.TYPE_GRAFT_ACK:
158 case PIM.TYPE_REGISTER:
159 case PIM.TYPE_REGISTER_STOP:
160 log.debug("Unsupported PIM message type: " + pim.getPimMsgType());
161 break;
162
163 default:
164 log.debug("Unkown PIM message type: " + pim.getPimMsgType());
165 break;
166 }
167 }
168
169 /**
170 * Process incoming hello message, we will need the Macaddress and IP address of the sender.
171 *
172 * @param ethPkt the ethernet header
173 * @param receivedFrom the connect point we recieved this message from
174 */
175 private void processHello(Ethernet ethPkt, ConnectPoint receivedFrom) {
176 checkNotNull(ethPkt);
177 checkNotNull(receivedFrom);
178
179 // It is a problem if we don't have the
180 PIMInterfaces pintfs = PIMInterfaces.getInstance();
181 PIMInterface intf = pintfs.getInterface(receivedFrom);
182 if (intf == null) {
183 log.error("We received a PIM message on an interface we were not supposed to");
184 return;
185 }
186 intf.processHello(ethPkt, receivedFrom);
187 }
188 }
189
190 // Create an ethernet header and serialize then send
191 public void sendPacket(PIM pim, PIMInterface pimIntf) {
192
193 Interface theInterface = pimIntf.getInterface();
194
195 // Create the ethernet packet
196 Ethernet eth = new Ethernet();
197 eth.setDestinationMACAddress(pimDestinationMac);
198 eth.setSourceMACAddress(theInterface.mac());
199 eth.setEtherType(Ethernet.TYPE_IPV4);
200 if (theInterface.vlan() != VlanId.NONE) {
201 eth.setVlanID(theInterface.vlan().toShort());
202 }
203
204 // Create the IP Packet
205 IPv4 ip = new IPv4();
206 ip.setVersion((byte) 4);
207 ip.setTtl((byte) 20);
208 ip.setProtocol(IPv4.PROTOCOL_PIM);
209 ip.setChecksum((short) 0);
210 ip.setSourceAddress(checkNotNull(pimIntf.getIpAddress()).getIp4Address().toInt());
211 ip.setDestinationAddress(PIM.PIM_ADDRESS.getIp4Address().toInt());
212 eth.setPayload(ip);
213 ip.setParent(eth);
214
215 // Now set pim
216 ip.setPayload(pim);
217 pim.setParent(ip);
218
219 ConnectPoint cp = theInterface.connectPoint();
220 checkNotNull(cp);
221
222 TrafficTreatment treat = DefaultTrafficTreatment.builder().setOutput(cp.port()).build();
223 ByteBuffer bb = ByteBuffer.wrap(eth.serialize());
224 OutboundPacket packet = new DefaultOutboundPacket(cp.deviceId(), treat, bb);
225 checkNotNull(packet);
226
227 packetService.emit(packet);
228 }
229}