2 * Copyright 2015 Open Networking Laboratory
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package org.onosproject.provider.netconf.flow.impl;
18 import static com.google.common.base.Strings.isNullOrEmpty;
19 import static org.onlab.util.Tools.get;
20 import static org.slf4j.LoggerFactory.getLogger;
23 import java.net.URISyntaxException;
24 import java.util.ArrayList;
25 import java.util.Collections;
26 import java.util.Dictionary;
27 import java.util.Enumeration;
28 import java.util.HashMap;
29 import java.util.List;
32 import java.util.concurrent.ConcurrentHashMap;
33 import java.util.concurrent.ConcurrentMap;
34 import java.util.concurrent.TimeUnit;
36 import org.apache.felix.scr.annotations.Activate;
37 import org.apache.felix.scr.annotations.Component;
38 import org.apache.felix.scr.annotations.Deactivate;
39 import org.apache.felix.scr.annotations.Modified;
40 import org.apache.felix.scr.annotations.Reference;
41 import org.apache.felix.scr.annotations.ReferenceCardinality;
42 import org.jboss.netty.util.HashedWheelTimer;
43 import org.jboss.netty.util.Timeout;
44 import org.jboss.netty.util.TimerTask;
45 import org.onlab.util.Timer;
46 import org.onosproject.core.ApplicationId;
47 import org.onosproject.net.DeviceId;
48 import org.onosproject.net.flow.FlowEntry;
49 import org.onosproject.net.flow.FlowRule;
50 import org.onosproject.net.flow.FlowRuleBatchOperation;
51 import org.onosproject.net.flow.FlowRuleProvider;
52 import org.onosproject.net.flow.FlowRuleProviderRegistry;
53 import org.onosproject.net.flow.FlowRuleProviderService;
54 import org.onosproject.net.provider.AbstractProvider;
55 import org.onosproject.net.provider.ProviderId;
56 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.AccessList;
57 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.AccessListBuilder;
58 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.AccessListEntries;
59 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.AccessListEntriesBuilder;
60 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.access.list.entries.ActionsBuilder;
61 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.access.list.entries.Matches;
62 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.access.list.entries.MatchesBuilder;
63 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.access.list.entries.actions.packet.handling.DenyBuilder;
64 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.access.list.entries.actions.packet.handling.PermitBuilder;
65 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.access.list.entries.matches.ace.type.AceIp;
66 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.acl.rev140520.access.list.access.list.entries.matches.ace.type.AceIpBuilder;
67 import 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;
68 import 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;
69 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
70 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
71 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.packet.fields.rev140625.acl.transport.header.fields.DestinationPortRange;
72 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.packet.fields.rev140625.acl.transport.header.fields.DestinationPortRangeBuilder;
73 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.packet.fields.rev140625.acl.transport.header.fields.SourcePortRange;
74 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.packet.fields.rev140625.acl.transport.header.fields.SourcePortRangeBuilder;
75 import org.osgi.service.component.ComponentContext;
76 import org.slf4j.Logger;
79 * Netconf provider to accept any flow and report them.
81 @Component(immediate = true)
82 public class NetconfFlowRuleProvider extends AbstractProvider
83 implements FlowRuleProvider {
84 private final Logger log = getLogger(getClass());
86 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
87 protected FlowRuleProviderRegistry providerRegistry;
89 private ConcurrentMap<DeviceId, Set<FlowEntry>> flowTable = new ConcurrentHashMap<>();
91 private FlowRuleProviderService providerService;
93 private XmlBuilder xmlBuilder;
96 private SourcePortRange srcPortRange;
97 private DestinationPortRange destPortRange;
98 private Matches matches;
99 private HashedWheelTimer timer = Timer.getTimer();
100 private Timeout timeout;
101 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";
111 public NetconfFlowRuleProvider() {
112 super(new ProviderId("netconf", "org.onosproject.provider.netconf"));
116 public void activate(ComponentContext context) {
117 providerService = providerRegistry.register(this);
118 timeout = timer.newTimeout(new StatisticTask(), 5, TimeUnit.SECONDS);
125 public void deactivate() {
126 providerRegistry.unregister(this);
127 providerService = null;
133 public void modified(ComponentContext context) {
134 if (xmlBuilder == null) {
135 xmlBuilder = new XmlBuilder();
137 if (context == null) {
138 log.info("No configuration file");
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));
151 nextElement = elements.nextElement();
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
171 private AccessList buildAccessList(Dictionary<?, ?> properties) {
173 * Populating Access List.
175 AccessListBuilder abuilder = new AccessListBuilder();
176 String aclName = get(properties, ACL_NAME_KEY);
177 if (aclName != null) {
178 abuilder.setAclName(aclName);
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);
193 private Matches getMatches(Dictionary<?, ?> properties) {
195 * Building Matches for given ACL model.
197 MatchesBuilder matchesBuilder = new MatchesBuilder();
199 matchesBuilder.setAceType(aceIp);
201 matches = matchesBuilder.build();
207 * @return srcPortRange
209 private SourcePortRange getSourcePortRange(Dictionary<?, ?> properties) {
211 * Building Source Port Range for given ACL model.
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));
220 if (spRangeUpperStr != null) {
221 int spRangeUpper = Integer.parseInt(spRangeUpperStr);
222 srcPortRangeBuilder.setUpperPort(new PortNumber(spRangeUpper));
224 srcPortRange = srcPortRangeBuilder.build();
230 * @return destPortRange
232 private DestinationPortRange getDestinationPortRange(Dictionary<?, ?> properties) {
234 * Building Destination Port Range for given ACL model.
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));
243 if (dpRangeUpperStr != null) {
244 int dpRangeUpper = Integer.parseInt(dpRangeUpperStr);
245 destPortRangeBuilder.setUpperPort(new PortNumber(dpRangeUpper));
247 destPortRange = destPortRangeBuilder.build();
248 return destPortRange;
253 * @return accessListEntries
255 private List<AccessListEntries> getAccessListEntries(Dictionary<?, ?> properties,
258 * Build and Populate Access List Entries.
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);
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());
277 acLListEntriesBuilder.setActions(actionBuilder.build());
279 AccessListEntries aclListEntries = acLListEntriesBuilder.build();
280 List<AccessListEntries> accessListEntries = new ArrayList<AccessListEntries>();
281 accessListEntries.add(aclListEntries);
282 return accessListEntries;
289 private AceIp getAceIp(Dictionary<?, ?> properties,
290 SourcePortRange srcPortRange,
291 DestinationPortRange destPortRange) {
293 * Building Ace IPV4 Type
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();
299 if (destIpv4 != null) {
300 Ipv4Prefix destinationIp = new Ipv4Prefix(destIpv4);
301 aceIpv4Builder.setDestinationIpv4Address(destinationIp);
303 if (srcIpv4 != null) {
304 Ipv4Prefix sourceIp = new Ipv4Prefix(srcIpv4);
305 aceIpv4Builder.setSourceIpv4Address(sourceIp);
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();
322 private Map<String, String> processDeviceEntry(String deviceEntry) {
323 if (deviceEntry == null) {
324 log.info("No content for Device Entry, so cannot proceed further.");
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");
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");
348 deviceMap.put("hostIp", hostIp);
349 deviceMap.put("hostPort", hostPort);
350 deviceMap.put("username", username);
351 deviceMap.put("password", password);
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'"
358 } catch (URISyntaxException urie) {
359 log.error("Error while parsing config information for the device entry: "
360 + "Illegal character in path " + deviceEntry,
362 } catch (Exception e) {
363 log.error("Error while parsing config information for the device entry: "
370 public void applyFlowRule(FlowRule... flowRules) {
374 public void removeFlowRule(FlowRule... flowRules) {
377 private void applyRule() {
378 // applyFlowRule(flowRules);//currentl
382 public void removeRulesById(ApplicationId id, FlowRule... flowRules) {
383 log.info("removal by app id not supported in null provider");
387 public void executeBatch(FlowRuleBatchOperation batch) {
391 private class StatisticTask implements TimerTask {
394 public void run(Timeout to) throws Exception {
395 for (DeviceId devId : flowTable.keySet()) {
396 providerService.pushFlowMetrics(devId, flowTable
397 .getOrDefault(devId, Collections.emptySet()));
399 timeout = timer.newTimeout(to.getTask(), 5, TimeUnit.SECONDS);