blob: b29d687e24cc547822b48c3e48caa95e7dc4ccdb [file] [log] [blame]
Sanjay Sbdd31302015-05-11 11:22:36 +05301/*
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.provider.netconf.flow.impl;
17
Samir Anand01c77c42015-08-06 14:50:29 +053018import static com.google.common.base.Strings.isNullOrEmpty;
19import static org.onlab.util.Tools.get;
Sanjay Sbdd31302015-05-11 11:22:36 +053020import static org.slf4j.LoggerFactory.getLogger;
21
Samir Anand01c77c42015-08-06 14:50:29 +053022import java.net.URI;
23import java.net.URISyntaxException;
24import java.util.ArrayList;
Sanjay Sbdd31302015-05-11 11:22:36 +053025import java.util.Collections;
Samir Anand01c77c42015-08-06 14:50:29 +053026import java.util.Dictionary;
27import java.util.Enumeration;
28import java.util.HashMap;
29import java.util.List;
30import java.util.Map;
Sanjay Sbdd31302015-05-11 11:22:36 +053031import java.util.Set;
32import java.util.concurrent.ConcurrentHashMap;
33import java.util.concurrent.ConcurrentMap;
34import java.util.concurrent.TimeUnit;
35
36import org.apache.felix.scr.annotations.Activate;
37import org.apache.felix.scr.annotations.Component;
38import org.apache.felix.scr.annotations.Deactivate;
39import org.apache.felix.scr.annotations.Modified;
40import org.apache.felix.scr.annotations.Reference;
41import org.apache.felix.scr.annotations.ReferenceCardinality;
42import org.jboss.netty.util.HashedWheelTimer;
43import org.jboss.netty.util.Timeout;
44import org.jboss.netty.util.TimerTask;
45import org.onlab.util.Timer;
46import org.onosproject.core.ApplicationId;
47import org.onosproject.net.DeviceId;
48import org.onosproject.net.flow.FlowEntry;
49import org.onosproject.net.flow.FlowRule;
50import org.onosproject.net.flow.FlowRuleBatchOperation;
51import org.onosproject.net.flow.FlowRuleProvider;
52import org.onosproject.net.flow.FlowRuleProviderRegistry;
53import org.onosproject.net.flow.FlowRuleProviderService;
54import org.onosproject.net.provider.AbstractProvider;
55import org.onosproject.net.provider.ProviderId;
Samir Anand01c77c42015-08-06 14:50:29 +053056import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.AccessList;
57import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.AccessListBuilder;
58import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.AccessListEntries;
59import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.AccessListEntriesBuilder;
60import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.access.list.entries.ActionsBuilder;
61import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.access.list.entries.Matches;
62import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.access.list.entries.MatchesBuilder;
63import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.access.list.entries.actions.packet.handling.DenyBuilder;
64import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.access.list.entries.actions.packet.handling.PermitBuilder;
65import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.access.list.entries.matches.ace.type.AceIp;
66import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.access.list.entries.matches.ace.type.AceIpBuilder;
67import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.access.list.entries.matches.ace.type.ace.ip.ace.ip.version.AceIpv4;
68import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.access.list.entries.matches.ace.type.ace.ip.ace.ip.version.AceIpv4Builder;
69import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
70import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
71import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.packet.fields.rev140625.acl.transport.header.fields.DestinationPortRange;
72import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.packet.fields.rev140625.acl.transport.header.fields.DestinationPortRangeBuilder;
73import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.packet.fields.rev140625.acl.transport.header.fields.SourcePortRange;
74import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.packet.fields.rev140625.acl.transport.header.fields.SourcePortRangeBuilder;
75import org.osgi.service.component.ComponentContext;
Sanjay Sbdd31302015-05-11 11:22:36 +053076import org.slf4j.Logger;
Samir Anand01c77c42015-08-06 14:50:29 +053077
Sanjay Sbdd31302015-05-11 11:22:36 +053078/**
79 * Netconf provider to accept any flow and report them.
80 */
81@Component(immediate = true)
82public class NetconfFlowRuleProvider extends AbstractProvider
83 implements FlowRuleProvider {
Sanjay Sbdd31302015-05-11 11:22:36 +053084 private final Logger log = getLogger(getClass());
85
86 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
87 protected FlowRuleProviderRegistry providerRegistry;
88
89 private ConcurrentMap<DeviceId, Set<FlowEntry>> flowTable = new ConcurrentHashMap<>();
90
91 private FlowRuleProviderService providerService;
92
Samir Anand01c77c42015-08-06 14:50:29 +053093 private XmlBuilder xmlBuilder;
94
95 private AceIp aceIp;
96 private SourcePortRange srcPortRange;
97 private DestinationPortRange destPortRange;
98 private Matches matches;
Sanjay Sbdd31302015-05-11 11:22:36 +053099 private HashedWheelTimer timer = Timer.getTimer();
100 private Timeout timeout;
Samir Anand01c77c42015-08-06 14:50:29 +0530101 private static final String ACL_NAME_KEY = "acl-name";
102 private static final String ACL_LIST_ENTRIES_RULE_NAME_KEY = "access-list-entries.rule-name";
103 private static final String ACL_LIST_SP_LOWER_KEY = "source-port-range.lower-port";
104 private static final String ACL_LIST_SP_UPPER_KEY = "source-port-range.upper-port";
105 private static final String ACL_LIST_DP_LOWER_KEY = "destination-port-range.lower-port";
106 private static final String ACL_LIST_DP_UPPER_KEY = "destination-port-range.upper-port";
107 private static final String ACL_LIST_DEST_IPV4_KEY = "matches.destination-ipv4-address";
108 private static final String ACL_LIST_SRC_IPV4_KEY = "matches.source-ipv4-address";
109 private static final String ACL_LIST_ACTIONS_KEY = "actions";
Sanjay Sbdd31302015-05-11 11:22:36 +0530110
111 public NetconfFlowRuleProvider() {
Samir Anand01c77c42015-08-06 14:50:29 +0530112 super(new ProviderId("netconf", "org.onosproject.provider.netconf"));
Sanjay Sbdd31302015-05-11 11:22:36 +0530113 }
114
115 @Activate
Samir Anand01c77c42015-08-06 14:50:29 +0530116 public void activate(ComponentContext context) {
Sanjay Sbdd31302015-05-11 11:22:36 +0530117 providerService = providerRegistry.register(this);
118 timeout = timer.newTimeout(new StatisticTask(), 5, TimeUnit.SECONDS);
119 applyRule();
Samir Anand01c77c42015-08-06 14:50:29 +0530120 modified(context);
Sanjay Sbdd31302015-05-11 11:22:36 +0530121 log.info("Started");
122 }
123
124 @Deactivate
125 public void deactivate() {
126 providerRegistry.unregister(this);
127 providerService = null;
128 timeout.cancel();
Sanjay Sbdd31302015-05-11 11:22:36 +0530129 log.info("Stopped");
130 }
131
132 @Modified
Samir Anand01c77c42015-08-06 14:50:29 +0530133 public void modified(ComponentContext context) {
134 if (xmlBuilder == null) {
135 xmlBuilder = new XmlBuilder();
136 }
137 if (context == null) {
138 log.info("No configuration file");
139 return;
140 }
141 Dictionary<?, ?> properties = context.getProperties();
142 String deviceEntry = get(properties, "devConfigs");
143 log.info("Settings: devConfigs={}", deviceEntry);
144 Enumeration<?> elements = properties.keys();
145 Object nextElement = elements.nextElement();
146 while (elements.hasMoreElements()) {
147 if (nextElement instanceof String) {
148 log.info("key::" + nextElement + ", value::"
149 + get(properties, (String) nextElement));
150 }
151 nextElement = elements.nextElement();
152 }
153 if (!isNullOrEmpty(deviceEntry)) {
154 Map<String, String> deviceMap = processDeviceEntry(deviceEntry);
155 AccessList accessList = buildAccessList(properties);
156 String xmlMsg = xmlBuilder.buildAclRequestXml(accessList);
157 log.info("The resultant xml from the builder\n" + xmlMsg);
158 NetconfOperation netconfOperation = new NetconfOperation();
159 netconfOperation.sendXmlMessage(xmlMsg, deviceMap.get("username"),
160 deviceMap.get("password"),
161 deviceMap.get("hostIp"), Integer
162 .parseInt(deviceMap
163 .get("hostPort")));
164 }
165 }
Sanjay Sbdd31302015-05-11 11:22:36 +0530166
Samir Anand01c77c42015-08-06 14:50:29 +0530167 /**
168 * @param properties
169 * @return accessList
170 */
171 private AccessList buildAccessList(Dictionary<?, ?> properties) {
172 /**
173 * Populating Access List.
174 */
175 AccessListBuilder abuilder = new AccessListBuilder();
176 String aclName = get(properties, ACL_NAME_KEY);
177 if (aclName != null) {
178 abuilder.setAclName(aclName);
179 }
180 AccessList accessList = abuilder.build();
181 abuilder.setAccessListEntries(getAccessListEntries(properties, matches));
182 srcPortRange = getSourcePortRange(properties);
183 destPortRange = getDestinationPortRange(properties);
184 aceIp = getAceIp(properties, srcPortRange, destPortRange);
185 matches = getMatches(properties);
186 return accessList;
187 }
188
189 /**
190 * @param properties
191 * @return matches
192 */
193 private Matches getMatches(Dictionary<?, ?> properties) {
194 /**
195 * Building Matches for given ACL model.
196 */
197 MatchesBuilder matchesBuilder = new MatchesBuilder();
198 if (aceIp != null) {
199 matchesBuilder.setAceType(aceIp);
200 }
201 matches = matchesBuilder.build();
202 return matches;
203 }
204
205 /**
206 * @param properties
207 * @return srcPortRange
208 */
209 private SourcePortRange getSourcePortRange(Dictionary<?, ?> properties) {
210 /**
211 * Building Source Port Range for given ACL model.
212 */
213 String spRangeLowerStr = get(properties, ACL_LIST_SP_LOWER_KEY);
214 String spRangeUpperStr = get(properties, ACL_LIST_SP_UPPER_KEY);
215 SourcePortRangeBuilder srcPortRangeBuilder = new SourcePortRangeBuilder();
216 if (spRangeLowerStr != null) {
217 int spRangeLower = Integer.parseInt(spRangeLowerStr);
218 srcPortRangeBuilder.setLowerPort(new PortNumber(spRangeLower));
219 }
220 if (spRangeUpperStr != null) {
221 int spRangeUpper = Integer.parseInt(spRangeUpperStr);
222 srcPortRangeBuilder.setUpperPort(new PortNumber(spRangeUpper));
223 }
224 srcPortRange = srcPortRangeBuilder.build();
225 return srcPortRange;
226 }
227
228 /**
229 * @param properties
230 * @return destPortRange
231 */
232 private DestinationPortRange getDestinationPortRange(Dictionary<?, ?> properties) {
233 /**
234 * Building Destination Port Range for given ACL model.
235 */
236 String dpRangeLowerStr = get(properties, ACL_LIST_DP_LOWER_KEY);
237 String dpRangeUpperStr = get(properties, ACL_LIST_DP_UPPER_KEY);
238 DestinationPortRangeBuilder destPortRangeBuilder = new DestinationPortRangeBuilder();
239 if (dpRangeLowerStr != null) {
240 int dpRangeLower = Integer.parseInt(dpRangeLowerStr);
241 destPortRangeBuilder.setLowerPort(new PortNumber(dpRangeLower));
242 }
243 if (dpRangeUpperStr != null) {
244 int dpRangeUpper = Integer.parseInt(dpRangeUpperStr);
245 destPortRangeBuilder.setUpperPort(new PortNumber(dpRangeUpper));
246 }
247 destPortRange = destPortRangeBuilder.build();
248 return destPortRange;
249 }
250
251 /**
252 * @param properties
253 * @return accessListEntries
254 */
255 private List<AccessListEntries> getAccessListEntries(Dictionary<?, ?> properties,
256 Matches matches) {
257 /**
258 * Build and Populate Access List Entries.
259 */
260 AccessListEntriesBuilder acLListEntriesBuilder = new AccessListEntriesBuilder();
261 String aclListEntriesRuleName = get(properties,
262 ACL_LIST_ENTRIES_RULE_NAME_KEY);
263 if (aclListEntriesRuleName != null) {
264 acLListEntriesBuilder.setRuleName(aclListEntriesRuleName);
265 }
266 acLListEntriesBuilder.setMatches(matches);
267 String aclActions = get(properties, ACL_LIST_ACTIONS_KEY);
268 if (aclActions != null) {
269 ActionsBuilder actionBuilder = new ActionsBuilder();
270 if (aclActions.equalsIgnoreCase("deny")) {
271 DenyBuilder denyBuilder = new DenyBuilder();
272 actionBuilder.setPacketHandling(denyBuilder.build());
273 } else if (aclActions.equalsIgnoreCase("permit")) {
274 PermitBuilder permitBuilder = new PermitBuilder();
275 actionBuilder.setPacketHandling(permitBuilder.build());
276 }
277 acLListEntriesBuilder.setActions(actionBuilder.build());
278 }
279 AccessListEntries aclListEntries = acLListEntriesBuilder.build();
280 List<AccessListEntries> accessListEntries = new ArrayList<AccessListEntries>();
281 accessListEntries.add(aclListEntries);
282 return accessListEntries;
283 }
284
285 /**
286 * @param properties
287 * @return aceIp
288 */
289 private AceIp getAceIp(Dictionary<?, ?> properties,
290 SourcePortRange srcPortRange,
291 DestinationPortRange destPortRange) {
292 /**
293 * Building Ace IPV4 Type
294 */
295 String destIpv4 = get(properties, ACL_LIST_DEST_IPV4_KEY);
296 String srcIpv4 = get(properties, ACL_LIST_SRC_IPV4_KEY);
297 AceIpv4Builder aceIpv4Builder = new AceIpv4Builder();
298 aceIp = null;
299 if (destIpv4 != null) {
300 Ipv4Prefix destinationIp = new Ipv4Prefix(destIpv4);
301 aceIpv4Builder.setDestinationIpv4Address(destinationIp);
302 }
303 if (srcIpv4 != null) {
304 Ipv4Prefix sourceIp = new Ipv4Prefix(srcIpv4);
305 aceIpv4Builder.setSourceIpv4Address(sourceIp);
306 }
307 if (destIpv4 != null || srcIpv4 != null) {
308 AceIpv4 aceIpv4 = aceIpv4Builder.build();
309 AceIpBuilder aceIpBuilder = new AceIpBuilder();
310 aceIpBuilder.setAceIpVersion(aceIpv4);
311 aceIpBuilder.setSourcePortRange(srcPortRange);
312 aceIpBuilder.setDestinationPortRange(destPortRange);
313 aceIp = aceIpBuilder.build();
314 }
315 return aceIp;
316 }
317
318 /**
319 * @param deviceEntry
320 * @return deviceMap
321 */
322 private Map<String, String> processDeviceEntry(String deviceEntry) {
323 if (deviceEntry == null) {
324 log.info("No content for Device Entry, so cannot proceed further.");
325 return null;
326 }
327
328 Map<String, String> deviceMap = new HashMap<String, String>();
329 log.info("Trying to convert Device Entry String: " + deviceEntry
330 + " to a Netconf Device Object");
331 try {
332 URI uri = new URI(deviceEntry);
333 String path = uri.getPath();
334 String userInfo = path.substring(path.lastIndexOf('@'));
335 String hostInfo = path.substring(path.lastIndexOf('@') + 1);
336 String[] infoSplit = userInfo.split(":");
337 String username = infoSplit[0];
338 String password = infoSplit[1];
339 infoSplit = hostInfo.split(":");
340 String hostIp = infoSplit[0];
341 String hostPort = infoSplit[1];
342 if (isNullOrEmpty(username) || isNullOrEmpty(password)
343 || isNullOrEmpty(hostIp) || isNullOrEmpty(hostPort)) {
344 log.warn("Bad Configuration Data: both user and device"
345 + " information parts of Configuration " + deviceEntry
346 + " should be non-nullable");
347 } else {
348 deviceMap.put("hostIp", hostIp);
349 deviceMap.put("hostPort", hostPort);
350 deviceMap.put("username", username);
351 deviceMap.put("password", password);
352 }
353 } catch (ArrayIndexOutOfBoundsException aie) {
354 log.error("Error while reading config infromation from the config file: "
355 + "The user, host and device state infomation should be "
356 + "in the order 'userInfo@hostInfo:deviceState'"
357 + deviceEntry, aie);
358 } catch (URISyntaxException urie) {
359 log.error("Error while parsing config information for the device entry: "
360 + "Illegal character in path " + deviceEntry,
361 urie);
362 } catch (Exception e) {
363 log.error("Error while parsing config information for the device entry: "
364 + deviceEntry, e);
365 }
366 return deviceMap;
Sanjay Sbdd31302015-05-11 11:22:36 +0530367 }
368
369 @Override
370 public void applyFlowRule(FlowRule... flowRules) {
Sanjay Sbdd31302015-05-11 11:22:36 +0530371 }
372
373 @Override
374 public void removeFlowRule(FlowRule... flowRules) {
Sanjay Sbdd31302015-05-11 11:22:36 +0530375 }
376
377 private void applyRule() {
378 // applyFlowRule(flowRules);//currentl
379 }
380
381 @Override
382 public void removeRulesById(ApplicationId id, FlowRule... flowRules) {
383 log.info("removal by app id not supported in null provider");
384 }
385
386 @Override
387 public void executeBatch(FlowRuleBatchOperation batch) {
388
389 }
390
391 private class StatisticTask implements TimerTask {
392
393 @Override
394 public void run(Timeout to) throws Exception {
395 for (DeviceId devId : flowTable.keySet()) {
396 providerService.pushFlowMetrics(devId, flowTable
397 .getOrDefault(devId, Collections.emptySet()));
398 }
399 timeout = timer.newTimeout(to.getTask(), 5, TimeUnit.SECONDS);
400
401 }
402 }
403}