blob: 5731b31156d013db4a1e4609380f4cb69338eb72 [file] [log] [blame]
gauravf0884562016-06-17 02:47:13 +05301/*
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 */
16package org.onosproject.dhcprelay;
17
18import java.util.Set;
19
20import org.apache.felix.scr.annotations.Activate;
21import org.apache.felix.scr.annotations.Component;
22import org.apache.felix.scr.annotations.Deactivate;
23import org.apache.felix.scr.annotations.Reference;
24import org.apache.felix.scr.annotations.ReferenceCardinality;
25import org.onlab.packet.DHCP;
26import org.onlab.packet.Ethernet;
27import org.onlab.packet.IPv4;
28import org.onlab.packet.TpPort;
29import org.onlab.packet.UDP;
30import org.onosproject.core.ApplicationId;
31import org.onosproject.core.CoreService;
32import org.onosproject.net.ConnectPoint;
33import org.onosproject.net.Host;
34import org.onosproject.net.HostId;
35import org.onosproject.net.config.ConfigFactory;
36import org.onosproject.net.config.NetworkConfigEvent;
37import org.onosproject.net.config.NetworkConfigListener;
38import org.onosproject.net.config.NetworkConfigRegistry;
39import org.onosproject.net.flow.DefaultTrafficSelector;
40import org.onosproject.net.flow.DefaultTrafficTreatment;
41import org.onosproject.net.flow.TrafficSelector;
42import org.onosproject.net.flow.TrafficTreatment;
43import org.onosproject.net.host.HostService;
44import org.onosproject.net.packet.DefaultOutboundPacket;
45import org.onosproject.net.packet.OutboundPacket;
46import org.onosproject.net.packet.PacketContext;
47import org.onosproject.net.packet.PacketPriority;
48import org.onosproject.net.packet.PacketProcessor;
49import org.onosproject.net.packet.PacketService;
50import org.slf4j.Logger;
51import org.slf4j.LoggerFactory;
52
53import com.google.common.collect.ImmutableSet;
54import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
55/**
56 * DHCP Relay Agent Application Component.
57 */
58@Component(immediate = true)
59public class DhcpRelay {
60
61 public static final String DHCP_RELAY_APP = "org.onosproject.dhcp-relay";
62 private final Logger log = LoggerFactory.getLogger(getClass());
63 private final InternalConfigListener cfgListener = new InternalConfigListener();
64
65 private final Set<ConfigFactory> factories = ImmutableSet.of(
66 new ConfigFactory<ApplicationId, DhcpRelayConfig>(APP_SUBJECT_FACTORY,
67 DhcpRelayConfig.class,
68 "dhcprelay") {
69 @Override
70 public DhcpRelayConfig createConfig() {
71 return new DhcpRelayConfig();
72 }
73 }
74 );
75
76 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
77 protected NetworkConfigRegistry cfgService;
78
79 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
80 protected CoreService coreService;
81
82 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
83 protected PacketService packetService;
84
85 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
86 protected HostService hostService;
87
88 private DhcpRelayPacketProcessor dhcpRelayPacketProcessor = new DhcpRelayPacketProcessor();
89 private ConnectPoint dhcpServerConnectPoint = null;
90 private ApplicationId appId;
91
92 @Activate
93 protected void activate() {
94 //start the dhcp relay agent
95
96 appId = coreService.registerApplication(DHCP_RELAY_APP);
97
98 cfgService.addListener(cfgListener);
99 factories.forEach(cfgService::registerConfigFactory);
100 //update the dhcp server configuration.
101 updateConfig();
102 //add the packet services.
103 packetService.addProcessor(dhcpRelayPacketProcessor, PacketProcessor.director(0));
104 requestPackets();
105 log.info("DHCP-RELAY Started");
106 log.info("started the apps dhcp relay");
107 }
108
109 @Deactivate
110 protected void deactivate() {
111 cfgService.removeListener(cfgListener);
112 factories.forEach(cfgService::unregisterConfigFactory);
113 packetService.removeProcessor(dhcpRelayPacketProcessor);
114 cancelPackets();
115 log.info("DHCP-RELAY Stopped");
116 }
117
118 private void updateConfig() {
119 DhcpRelayConfig cfg = cfgService.getConfig(appId, DhcpRelayConfig.class);
120
121 if (cfg == null) {
122 log.warn("Dhcp Server info not available");
123 return;
124 }
125
126 dhcpServerConnectPoint = cfg.getDhcpServerConnectPoint();
127 log.info("Reconfigured the dhcp server info");
128 log.info("dhcp server connect points are " + dhcpServerConnectPoint);
129 }
130
131 /**
132 * Request packet in via PacketService.
133 */
134 private void requestPackets() {
135
136 TrafficSelector.Builder selectorServer = DefaultTrafficSelector.builder()
137 .matchEthType(Ethernet.TYPE_IPV4)
138 .matchIPProtocol(IPv4.PROTOCOL_UDP)
139 .matchUdpDst(TpPort.tpPort(UDP.DHCP_SERVER_PORT))
140 .matchUdpSrc(TpPort.tpPort(UDP.DHCP_CLIENT_PORT));
141 packetService.requestPackets(selectorServer.build(), PacketPriority.CONTROL, appId);
142
143 TrafficSelector.Builder selectorClient = DefaultTrafficSelector.builder()
144 .matchEthType(Ethernet.TYPE_IPV4)
145 .matchIPProtocol(IPv4.PROTOCOL_UDP)
146 .matchUdpDst(TpPort.tpPort(UDP.DHCP_CLIENT_PORT))
147 .matchUdpSrc(TpPort.tpPort(UDP.DHCP_SERVER_PORT));
148 packetService.requestPackets(selectorClient.build(), PacketPriority.CONTROL, appId);
149 }
150
151 /**
152 * Cancel requested packets in via packet service.
153 */
154 private void cancelPackets() {
155 TrafficSelector.Builder selectorServer = DefaultTrafficSelector.builder()
156 .matchEthType(Ethernet.TYPE_IPV4)
157 .matchIPProtocol(IPv4.PROTOCOL_UDP)
158 .matchUdpDst(TpPort.tpPort(UDP.DHCP_SERVER_PORT))
159 .matchUdpSrc(TpPort.tpPort(UDP.DHCP_CLIENT_PORT));
160 packetService.cancelPackets(selectorServer.build(), PacketPriority.CONTROL, appId);
161
162 TrafficSelector.Builder selectorClient = DefaultTrafficSelector.builder()
163 .matchEthType(Ethernet.TYPE_IPV4)
164 .matchIPProtocol(IPv4.PROTOCOL_UDP)
165 .matchUdpDst(TpPort.tpPort(UDP.DHCP_CLIENT_PORT))
166 .matchUdpSrc(TpPort.tpPort(UDP.DHCP_SERVER_PORT));
167 packetService.cancelPackets(selectorClient.build(), PacketPriority.CONTROL, appId);
168 }
169
170 private class DhcpRelayPacketProcessor implements PacketProcessor {
171
172 @Override
173 public void process(PacketContext context) {
174 // process the packet and get the payload
175 Ethernet packet = context.inPacket().parsed();
176
177 if (packet == null) {
178 return;
179 }
180
181 if (packet.getEtherType() == Ethernet.TYPE_IPV4) {
182 IPv4 ipv4Packet = (IPv4) packet.getPayload();
183
184 if (ipv4Packet.getProtocol() == IPv4.PROTOCOL_UDP) {
185 UDP udpPacket = (UDP) ipv4Packet.getPayload();
186 DHCP dhcpPayload = (DHCP) udpPacket.getPayload();
187 if (udpPacket.getDestinationPort() == UDP.DHCP_SERVER_PORT &&
188 udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT) {
189 //This packet is dhcp client request.
190 forwardPacket(context, dhcpPayload);
191 } else {
192 //This packet is a dhcp reply from DHCP server.
193 sendReply(context, dhcpPayload);
194 }
195 }
196 }
197 }
198
199 //forward the packet to ConnectPoint where the DHCP server is attached.
200 private void forwardPacket(PacketContext context, DHCP dhcpPayload) {
201 if (dhcpPayload == null) {
202 log.debug("DHCP packet without payload, do nothing");
203 return;
204 }
205
206 //send Packetout to dhcp server connectpoint.
207 if (dhcpServerConnectPoint != null) {
208 TrafficTreatment t = DefaultTrafficTreatment.builder()
209 .setOutput(dhcpServerConnectPoint.port()).build();
210 OutboundPacket o = new DefaultOutboundPacket(
211 dhcpServerConnectPoint.deviceId(), t, context.inPacket().unparsed());
212 packetService.emit(o);
213 }
214 }
215
216 /*//process the dhcp packet before sending to server
217 private void processDhcpPacket(PacketContext context, DHCP dhcpPayload) {
218 if (dhcpPayload == null) {
219 return;
220 }
221 Ethernet packet = context.inPacket().parsed();
222 DHCPPacketType incomingPacketType = null;
223 for (DHCPOption option : dhcpPayload.getOptions()) {
224 if (option.getCode() == OptionCode_MessageType.getValue()) {
225 byte[] data = option.getData();
226 incomingPacketType = DHCPPacketType.getType(data[0]);
227 }
228 }
229 switch (incomingPacketType) {
230 case DHCPDISCOVER:
231 break;
232 default:
233 break;
234 }
235 }*/
236
237 //send the response to the requestor host.
238 private void sendReply(PacketContext context, DHCP dhcpPayload) {
239 if (dhcpPayload == null) {
240 log.debug("DHCP packet without payload, do nothing");
241 return;
242 }
243 //get the host info
244 Ethernet packet = context.inPacket().parsed();
245 Host host = hostService.getHost(HostId.hostId(packet.getDestinationMAC()));
246 ConnectPoint dhcpRequestor = new ConnectPoint(host.location().elementId(),
247 host.location().port());
248
249 //send Packetout to requestor host.
250 if (dhcpRequestor != null) {
251 TrafficTreatment t = DefaultTrafficTreatment.builder()
252 .setOutput(dhcpRequestor.port()).build();
253 OutboundPacket o = new DefaultOutboundPacket(
254 dhcpRequestor.deviceId(), t, context.inPacket().unparsed());
255 packetService.emit(o);
256 }
257 }
258 }
259
260 /**
261 * Listener for network config events.
262 */
263 private class InternalConfigListener implements NetworkConfigListener {
264
265 @Override
266 public void event(NetworkConfigEvent event) {
267
268 if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
269 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
270 event.configClass().equals(DhcpRelayConfig.class)) {
271 updateConfig();
272 log.info("Reconfigured");
273 }
274 }
275 }
276}