b29d687e24cc547822b48c3e48caa95e7dc4ccdb
[onosfw.git] /
1 /*
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  */
16 package org.onosproject.provider.netconf.flow.impl;
17
18 import static com.google.common.base.Strings.isNullOrEmpty;
19 import static org.onlab.util.Tools.get;
20 import static org.slf4j.LoggerFactory.getLogger;
21
22 import java.net.URI;
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;
30 import java.util.Map;
31 import java.util.Set;
32 import java.util.concurrent.ConcurrentHashMap;
33 import java.util.concurrent.ConcurrentMap;
34 import java.util.concurrent.TimeUnit;
35
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;
77
78 /**
79  * Netconf provider to accept any flow and report them.
80  */
81 @Component(immediate = true)
82 public class NetconfFlowRuleProvider extends AbstractProvider
83         implements FlowRuleProvider {
84     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
93     private XmlBuilder xmlBuilder;
94
95     private AceIp aceIp;
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";
110
111     public NetconfFlowRuleProvider() {
112         super(new ProviderId("netconf", "org.onosproject.provider.netconf"));
113     }
114
115     @Activate
116     public void activate(ComponentContext context) {
117         providerService = providerRegistry.register(this);
118         timeout = timer.newTimeout(new StatisticTask(), 5, TimeUnit.SECONDS);
119         applyRule();
120         modified(context);
121         log.info("Started");
122     }
123
124     @Deactivate
125     public void deactivate() {
126         providerRegistry.unregister(this);
127         providerService = null;
128         timeout.cancel();
129         log.info("Stopped");
130     }
131
132     @Modified
133     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     }
166
167     /**
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;
367     }
368
369     @Override
370     public void applyFlowRule(FlowRule... flowRules) {
371     }
372
373     @Override
374     public void removeFlowRule(FlowRule... flowRules) {
375     }
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 }