blob: db46d8dcb632ed2dcb3b152ec0d818ea062af7c2 [file] [log] [blame]
hiroki337c5522019-01-20 20:05:51 -08001/*
2 * Copyright 2018-present Open Networking Foundation
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 * This work was partially supported by EC H2020 project METRO-HAUL (761727).
17 */
18
19package org.onosproject.drivers.odtn;
20
21import com.google.common.collect.ImmutableList;
22import org.onlab.util.Frequency;
Andrea Campanellabb66e092019-01-28 13:50:06 +010023import org.onosproject.drivers.odtn.impl.DeviceConnectionCache;
Andrea Campanella3a361452019-08-02 10:17:53 +020024import org.onosproject.drivers.odtn.impl.FlowRuleParser;
hiroki337c5522019-01-20 20:05:51 -080025import org.onosproject.net.DeviceId;
26import org.onosproject.net.Port;
27import org.onosproject.net.PortNumber;
28import org.onosproject.net.device.DeviceService;
29import org.onosproject.net.driver.AbstractHandlerBehaviour;
30import org.onosproject.net.flow.DefaultFlowEntry;
31import org.onosproject.net.flow.FlowEntry;
32import org.onosproject.net.flow.FlowRule;
33import org.onosproject.net.flow.FlowRuleProgrammable;
34import org.onosproject.netconf.DatastoreId;
35import org.onosproject.netconf.NetconfController;
36import org.onosproject.netconf.NetconfException;
37import org.onosproject.netconf.NetconfSession;
38import org.slf4j.Logger;
39import org.slf4j.LoggerFactory;
40
41import java.util.ArrayList;
42import java.util.Collection;
43import java.util.List;
44
45import static com.google.common.base.Preconditions.checkNotNull;
46import static org.onosproject.odtn.behaviour.OdtnDeviceDescriptionDiscovery.OC_NAME;
47
48/**
49 * Implementation of FlowRuleProgrammable interface for
50 * OpenConfig terminal devices.
51 */
52public class CassiniFlowRuleProgrammable
53 extends AbstractHandlerBehaviour implements FlowRuleProgrammable {
54
55 private static final Logger log =
56 LoggerFactory.getLogger(CassiniFlowRuleProgrammable.class);
57
58 /**
59 * Apply the flow entries specified in the collection rules.
60 *
61 * @param rules A collection of Flow Rules to be applied
62 * @return The collection of added Flow Entries
63 */
64 @Override
65 public Collection<FlowRule> applyFlowRules(Collection<FlowRule> rules) {
66 NetconfSession session = getNetconfSession();
67 if (session == null) {
68 openConfigError("null session");
69 return ImmutableList.of();
70 }
71 List<FlowRule> added = new ArrayList<>();
72 for (FlowRule r : rules) {
73 try {
Andrea Campanellabb66e092019-01-28 13:50:06 +010074 String connectionId = applyFlowRule(session, r);
75 getConnectionCache().add(did(), connectionId, r);
76 added.add(r);
hiroki337c5522019-01-20 20:05:51 -080077 } catch (Exception e) {
78 openConfigError("Error {}", e);
79 continue;
80 }
hiroki337c5522019-01-20 20:05:51 -080081 }
82 openConfigLog("applyFlowRules added {}", added.size());
83 return added;
84 }
85
86 /**
87 * Get the flow entries that are present on the device.
88 *
89 * @return A collection of Flow Entries
90 */
91 @Override
92 public Collection<FlowEntry> getFlowEntries() {
Andrea Campanellabb66e092019-01-28 13:50:06 +010093 DeviceConnectionCache cache = getConnectionCache();
hiroki337c5522019-01-20 20:05:51 -080094 if (cache.get(did()) == null) {
95 return ImmutableList.of();
96 }
97
98 List<FlowEntry> entries = new ArrayList<>();
99 for (FlowRule r : cache.get(did())) {
100 entries.add(
101 new DefaultFlowEntry(r, FlowEntry.FlowEntryState.ADDED, 0, 0, 0));
102 }
103 return entries;
104 }
105
106 /**
107 * Remove the specified flow rules.
108 *
109 * @param rules A collection of Flow Rules to be removed
110 * @return The collection of removed Flow Entries
111 */
112 @Override
113 public Collection<FlowRule> removeFlowRules(Collection<FlowRule> rules) {
114 NetconfSession session = getNetconfSession();
115 if (session == null) {
116 openConfigError("null session");
117 return ImmutableList.of();
118 }
119 List<FlowRule> removed = new ArrayList<>();
120 for (FlowRule r : rules) {
121 try {
Andrea Campanellabb66e092019-01-28 13:50:06 +0100122 String connectionId = removeFlowRule(session, r);
123 getConnectionCache().remove(did(), connectionId);
124 removed.add(r);
hiroki337c5522019-01-20 20:05:51 -0800125 } catch (Exception e) {
126 openConfigError("Error {}", e);
127 continue;
128 }
hiroki337c5522019-01-20 20:05:51 -0800129 }
130 openConfigLog("removedFlowRules removed {}", removed.size());
131 return removed;
132 }
133
Andrea Campanellabb66e092019-01-28 13:50:06 +0100134 private DeviceConnectionCache getConnectionCache() {
135 return DeviceConnectionCache.init();
hiroki337c5522019-01-20 20:05:51 -0800136 }
137
138 /**
139 * Helper method to get the device id.
140 */
141 private DeviceId did() {
142 return data().deviceId();
143 }
144
145 /**
146 * Helper method to log from this class adding DeviceId.
147 */
148 private void openConfigLog(String format, Object... arguments) {
149 log.info("OPENCONFIG {}: " + format, did(), arguments);
150 }
151
152 /**
153 * Helper method to log an error from this class adding DeviceId.
154 */
155 private void openConfigError(String format, Object... arguments) {
156 log.error("OPENCONFIG {}: " + format, did(), arguments);
157 }
158
159
160 /**
161 * Helper method to get the Netconf Session.
162 */
163 private NetconfSession getNetconfSession() {
164 NetconfController controller =
165 checkNotNull(handler().get(NetconfController.class));
166 return controller.getNetconfDevice(did()).getSession();
167 }
168
169 private void setOpticalChannelFrequency(NetconfSession session,
170 String optChannel, Frequency freq)
171 throws NetconfException {
172 StringBuilder sb = new StringBuilder();
173 sb.append(
174 "<components xmlns='http://openconfig.net/yang/platform'>"
Boyuan Yan8f9f6ad2019-06-12 16:54:42 -0700175 + "<component nc:operation='merge'>"
hiroki337c5522019-01-20 20:05:51 -0800176 + "<name>" + optChannel + "</name>"
177 + "<oc-opt-term:optical-channel "
178 +
179 " xmlns:oc-opt-term='http://openconfig.net/yang/terminal-device'>"
180 + " <oc-opt-term:config>"
181 + " <oc-opt-term:frequency>" + (long) freq.asMHz() +
182 "</oc-opt-term:frequency>"
183 + " </oc-opt-term:config>"
184 + " </oc-opt-term:optical-channel>"
185 + "</component>"
186 + "</components>");
Andrea Campanella3a361452019-08-02 10:17:53 +0200187 log.info("Optical Channel Frequency {}", sb.toString());
188 boolean ok = session.editConfig(DatastoreId.CANDIDATE, null, sb.toString());
hiroki337c5522019-01-20 20:05:51 -0800189 if (!ok) {
190 throw new NetconfException("error writing channel frequency");
191 }
Andrea Campanella3a361452019-08-02 10:17:53 +0200192 ok = session.commit();
193 if (!ok) {
194 throw new NetconfException("error committing channel frequency");
195 }
hiroki337c5522019-01-20 20:05:51 -0800196 }
197
198 /**
199 * Get the OpenConfig component name for the OpticalChannel component.
200 *
201 * @param portNumber ONOS port number of the Line port ().
202 * @return the channel component name or null
203 */
204 private String getOpticalChannel(PortNumber portNumber) {
205 Port clientPort = handler().get(DeviceService.class).getPort(did(), portNumber);
206 return clientPort.annotations().value(OC_NAME);
207 }
208
209 /**
210 * Apply the flowrule.
Andrea Campanella3a361452019-08-02 10:17:53 +0200211 * <p>
hiroki337c5522019-01-20 20:05:51 -0800212 * Note: only bidirectional are supported as of now,
213 * given OpenConfig note (below). In consequence, only the
214 * TX rules are actually mapped to netconf ops.
215 * <p>
216 * https://github.com/openconfig/public/blob/master/release/models
217 * /optical-transport/openconfig-terminal-device.yang
218 * <p>
219 * Directionality:
220 * To maintain simplicity in the model, the configuration is
221 * described from client-to-line direction. The assumption is that
222 * equivalent reverse configuration is implicit, resulting in
223 * the same line-to-client configuration.
224 *
225 * @param session The Netconf session.
226 * @param r Flow Rules to be applied.
Andrea Campanellabb66e092019-01-28 13:50:06 +0100227 * @return the optical channel + the frequency or just channel as identifier fo the config installed on the device
hiroki337c5522019-01-20 20:05:51 -0800228 * @throws NetconfException if exchange goes wrong
229 */
Andrea Campanellabb66e092019-01-28 13:50:06 +0100230 protected String applyFlowRule(NetconfSession session, FlowRule r) throws NetconfException {
hiroki337c5522019-01-20 20:05:51 -0800231 FlowRuleParser frp = new FlowRuleParser(r);
232 if (!frp.isReceiver()) {
233 String optChannel = getOpticalChannel(frp.getPortNumber());
Andrea Campanellabb66e092019-01-28 13:50:06 +0100234 setOpticalChannelFrequency(session, optChannel,
235 frp.getCentralFrequency());
236 return optChannel + ":" + frp.getCentralFrequency().asGHz();
hiroki337c5522019-01-20 20:05:51 -0800237 }
Andrea Campanellabb66e092019-01-28 13:50:06 +0100238 return String.valueOf(frp.getCentralFrequency().asGHz());
hiroki337c5522019-01-20 20:05:51 -0800239 }
240
241
Andrea Campanellabb66e092019-01-28 13:50:06 +0100242 protected String removeFlowRule(NetconfSession session, FlowRule r)
hiroki337c5522019-01-20 20:05:51 -0800243 throws NetconfException {
244 FlowRuleParser frp = new FlowRuleParser(r);
245 if (!frp.isReceiver()) {
246 String optChannel = getOpticalChannel(frp.getPortNumber());
247 setOpticalChannelFrequency(session, optChannel, Frequency.ofMHz(0));
Andrea Campanellabb66e092019-01-28 13:50:06 +0100248 return optChannel + ":" + frp.getCentralFrequency().asGHz();
hiroki337c5522019-01-20 20:05:51 -0800249 }
Andrea Campanellabb66e092019-01-28 13:50:06 +0100250 return String.valueOf(frp.getCentralFrequency().asGHz());
hiroki337c5522019-01-20 20:05:51 -0800251 }
252}