blob: 8f75100e109d834c7de5b2907208633ec0f23dfa [file] [log] [blame]
hirokib8ddc3f2018-06-02 08:29:42 -07001/*
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
17package org.onosproject.odtn.internal;
18
19import java.util.ArrayList;
20import java.util.List;
21import java.util.Optional;
22import org.onosproject.net.DeviceId;
23import org.onosproject.net.PortNumber;
24import org.onosproject.net.device.DeviceService;
25import org.onosproject.netconf.NetconfDevice;
26import org.onosproject.netconf.NetconfException;
27import org.onosproject.odtn.behaviour.ConfigurableTransceiver;
28import org.onosproject.odtn.behaviour.OdtnTerminalDeviceDriver;
29import org.onosproject.odtn.behaviour.PlainTransceiver;
30
31import static com.google.common.base.Preconditions.checkNotNull;
32import static org.onlab.osgi.DefaultServiceDirectory.getService;
33
34import static org.onosproject.odtn.utils.YangToolUtil.toCharSequence;
35import static org.onosproject.odtn.utils.YangToolUtil.toDocument;
36
37import javax.xml.parsers.DocumentBuilderFactory;
38import javax.xml.parsers.ParserConfigurationException;
39
40import org.onlab.util.XmlString;
41import org.onosproject.netconf.NetconfController;
42import org.w3c.dom.Document;
43import org.w3c.dom.Element;
44
45import com.google.common.io.CharSource;
46
47import org.slf4j.Logger;
48import org.slf4j.LoggerFactory;
49
50
51/**
52 * Device driver implementation for ODTN Phase1.0.
53 * <p>
54 * NETCONF SB should be provided by DCS, but currently DCS SB driver have
55 * some critical problem to configure actual devices and netconf servers,
56 * as a workaround this posts netconf edit-config directly.
57 */
58public final class DefaultOdtnTerminalDeviceDriver implements OdtnTerminalDeviceDriver {
59
60 protected final Logger log = LoggerFactory.getLogger(getClass());
61
62 private DeviceService deviceService;
63
64 private DefaultOdtnTerminalDeviceDriver() {
65 }
66
67 public static DefaultOdtnTerminalDeviceDriver create() {
68 DefaultOdtnTerminalDeviceDriver self = new DefaultOdtnTerminalDeviceDriver();
69 self.deviceService = getService(DeviceService.class);
70 return self;
71 }
72
73 @Override
74 public void apply(DeviceId did, PortNumber client, PortNumber line, boolean enable) {
75
76 checkNotNull(did);
77 checkNotNull(client);
78 checkNotNull(line);
79
80 List<CharSequence> nodes = new ArrayList<>();
81
82 ConfigurableTransceiver transceiver =
83 Optional.ofNullable(did)
84 .map(deviceService::getDevice)
85 .filter(device -> device.is(ConfigurableTransceiver.class))
86 .map(device -> device.as(ConfigurableTransceiver.class))
87 .orElseGet(() -> new PlainTransceiver());
88
89 nodes.addAll(transceiver.enable(client, line, enable));
90 if (nodes.size() == 0) {
91 log.warn("Nothing to be configured.");
92 return;
93 }
94
95 Document doc = buildEditConfigBody(nodes);
96 configureDevice(did, doc);
97 }
98
99 private Document buildEditConfigBody(List<CharSequence> nodes) {
100
101 Document doc;
102 try {
103 doc = DocumentBuilderFactory.newInstance()
104 .newDocumentBuilder().newDocument();
105 } catch (ParserConfigurationException e) {
106 log.error("Unexpected error", e);
107 throw new IllegalStateException(e);
108 }
109
110 Element config = addEditConfigEnvelope(doc);
111
112 for (CharSequence node : nodes) {
113 Document ldoc = toDocument(CharSource.wrap(node));
114 Element cfgRoot = ldoc.getDocumentElement();
115
116 cfgRoot.setAttribute("xc:operation", Operation.MERGE.value());
117
118 // move (or copy) node to another Document
119 config.appendChild(Optional.ofNullable(doc.adoptNode(cfgRoot))
120 .orElseGet(() -> doc.importNode(cfgRoot, true)));
121
122 }
123
124 log.info("XML:\n{}", XmlString.prettifyXml(toCharSequence(doc)));
125 return doc;
126 }
127
128 private Element addEditConfigEnvelope(Document doc) {
129
130 // netconf rpc boilerplate part without message-id
131 Element rpc = doc.createElementNS("urn:ietf:params:xml:ns:netconf:base:1.0", "rpc");
132 doc.appendChild(rpc);
133 Element editConfig = doc.createElement("edit-config");
134 rpc.appendChild(editConfig);
135 Element target = doc.createElement("target");
136 editConfig.appendChild(target);
137 target.appendChild(doc.createElement("running"));
138
139 Element config = doc.createElement("config");
140 config.setAttributeNS("http://www.w3.org/2000/xmlns/",
141 "xmlns:xc",
142 "urn:ietf:params:xml:ns:netconf:base:1.0");
143 editConfig.appendChild(config);
144
145 return config;
146 }
147
148 private void configureDevice(DeviceId did, Document doc) {
149
150 NetconfController ctr = getService(NetconfController.class);
151 Optional.ofNullable(ctr.getNetconfDevice(did))
152 .map(NetconfDevice::getSession)
153 .ifPresent(session -> {
154 try {
155 session.rpc(toCharSequence(doc, false).toString()).join();
156 } catch (NetconfException e) {
157 log.error("Exception thrown", e);
158 }
159 });
160 }
161
162}