blob: 0133f6faaa05c82b17296b4d3b853185a0c71d3b [file] [log] [blame]
Thomas Vachuska58de4162015-09-10 16:15:33 -07001/*
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 */
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070016package org.onosproject.segmentrouting.config;
17
18import java.io.File;
19import java.io.IOException;
20import java.util.ArrayList;
21import java.util.HashMap;
22import java.util.HashSet;
23import java.util.List;
24import java.util.Map;
25import java.util.Set;
26import java.util.concurrent.ConcurrentHashMap;
27import java.util.concurrent.ConcurrentMap;
28
29import org.onosproject.net.DeviceId;
30import org.onosproject.net.Link;
31import org.onosproject.segmentrouting.config.NetworkConfig.LinkConfig;
32import org.onosproject.segmentrouting.config.NetworkConfig.SwitchConfig;
33import org.slf4j.Logger;
34import org.slf4j.LoggerFactory;
35
36import com.fasterxml.jackson.core.JsonParseException;
37import com.fasterxml.jackson.databind.JsonMappingException;
38import com.fasterxml.jackson.databind.ObjectMapper;
39
40/**
41 * NetworkConfigManager manages all network configuration for switches, links
42 * and any other state that needs to be configured for correct network
43 * operation.
44 *
45 */
46public class NetworkConfigManager implements NetworkConfigService {
47 protected static final Logger log = LoggerFactory
48 .getLogger(NetworkConfigManager.class);
49 private static final String CONFIG_DIR = "../config";
50 private static final String DEFAULT_CONFIG_FILE = "segmentrouting.conf";
51 private final String configFileName = DEFAULT_CONFIG_FILE;
52 /**
53 * JSON Config file needs to use one of the following types for defining the
54 * kind of switch or link it wishes to configure.
55 */
56 public static final String SEGMENT_ROUTER = "Router_SR";
57
58 public static final String PKT_LINK = "pktLink";
59
60 NetworkConfig networkConfig;
61 private ConcurrentMap<DeviceId, SwitchConfig> configuredSwitches;
62 private ConcurrentMap<Link, LinkConfig> configuredLinks;
63 private Map<String, DeviceId> nameToDpid;
64
65 @Override
66 public SwitchConfigStatus checkSwitchConfig(DeviceId dpid) {
67 SwitchConfig swc = configuredSwitches.get(dpid);
68 if (networkConfig.getRestrictSwitches()) {
69 // default deny behavior
70 if (swc == null) {
71 // switch is not configured - we deny this switch
72 return new SwitchConfigStatus(NetworkConfigState.DENY, null,
73 "Switch not configured, in network denying switches by default.");
74 }
75 if (swc.isAllowed()) {
76 // switch is allowed in config, return configured attributes
77 return new SwitchConfigStatus(NetworkConfigState.ACCEPT_ADD, swc);
78 } else {
79 // switch has been configured off (administratively down)
80 return new SwitchConfigStatus(NetworkConfigState.DENY, null,
81 "Switch configured down (allowed=false).");
82 }
83 } else {
84 // default allow behavior
85 if (swc == null) {
86 // no config to add
87 return new SwitchConfigStatus(NetworkConfigState.ACCEPT, null);
88 }
89 if (swc.isAllowed()) {
90 // switch is allowed in config, return configured attributes
91 return new SwitchConfigStatus(NetworkConfigState.ACCEPT_ADD, swc);
92 } else {
93 // switch has been configured off (administratively down)
94 return new SwitchConfigStatus(NetworkConfigState.DENY, null,
95 "Switch configured down (allowed=false).");
96 }
97 }
98
99 }
100
101 @Override
102 public LinkConfigStatus checkLinkConfig(Link linkTuple) {
103 LinkConfig lkc = getConfiguredLink(linkTuple);
104 // links are always disallowed if any one of the nodes that make up the
105 // link are disallowed
106 DeviceId linkNode1 = linkTuple.src().deviceId();
107 SwitchConfigStatus scs1 = checkSwitchConfig(linkNode1);
108 if (scs1.getConfigState() == NetworkConfigState.DENY) {
109 return new LinkConfigStatus(NetworkConfigState.DENY, null,
110 "Link-node: " + linkNode1 + " denied by config: " + scs1.getMsg());
111 }
112 DeviceId linkNode2 = linkTuple.dst().deviceId();
113 SwitchConfigStatus scs2 = checkSwitchConfig(linkNode2);
114 if (scs2.getConfigState() == NetworkConfigState.DENY) {
115 return new LinkConfigStatus(NetworkConfigState.DENY, null,
116 "Link-node: " + linkNode2 + " denied by config: " + scs2.getMsg());
117 }
118 if (networkConfig.getRestrictLinks()) {
119 // default deny behavior
120 if (lkc == null) {
121 // link is not configured - we deny this link
122 return new LinkConfigStatus(NetworkConfigState.DENY, null,
123 "Link not configured, in network denying links by default.");
124 }
125 if (lkc.isAllowed()) {
126 // link is allowed in config, return configured attributes
127 return new LinkConfigStatus(NetworkConfigState.ACCEPT_ADD, lkc);
128 } else {
129 // link has been configured off (administratively down)
130 return new LinkConfigStatus(NetworkConfigState.DENY, null,
131 "Link configured down (allowed=false).");
132 }
133 } else {
134 // default allow behavior
135 if (lkc == null) {
136 // no config to add
137 return new LinkConfigStatus(NetworkConfigState.ACCEPT, null);
138 }
139 if (lkc.isAllowed()) {
140 // link is allowed in config, return configured attributes
141 return new LinkConfigStatus(NetworkConfigState.ACCEPT_ADD, lkc);
142 } else {
143 // link has been configured off (administratively down)
144 return new LinkConfigStatus(NetworkConfigState.DENY, null,
145 "Link configured down (allowed=false).");
146 }
147 }
148
149 }
150
151 @Override
152 public List<SwitchConfig> getConfiguredAllowedSwitches() {
153 List<SwitchConfig> allowed = new ArrayList<SwitchConfig>();
154 for (SwitchConfig swc : configuredSwitches.values()) {
155 if (swc.isAllowed()) {
156 allowed.add(swc);
157 }
158 }
159 return allowed;
160 }
161
162 @Override
163 public List<LinkConfig> getConfiguredAllowedLinks() {
164 List<LinkConfig> allowed = new ArrayList<LinkConfig>();
165 for (LinkConfig lkc : configuredLinks.values()) {
166 if (lkc.isAllowed()) {
167 allowed.add(lkc);
168 }
169 }
170 return allowed;
171 }
172
173 @Override
174 public DeviceId getDpidForName(String name) {
175 if (nameToDpid.get(name) != null) {
176 return nameToDpid.get(name);
177 }
178 return null;
179 }
180
181 // **************
182 // Private methods
183 // **************
184
185 private void loadNetworkConfig() {
186 File configFile = new File(CONFIG_DIR, configFileName);
187 ObjectMapper mapper = new ObjectMapper();
188 networkConfig = new NetworkConfig();
189
190 try {
191 networkConfig = mapper.readValue(configFile,
192 NetworkConfig.class);
193 } catch (JsonParseException e) {
194 String err = String.format("JsonParseException while loading network "
195 + "config from file: %s: %s", configFileName,
196 e.getMessage());
197 throw new NetworkConfigException.ErrorConfig(err);
198 } catch (JsonMappingException e) {
199 String err = String.format(
200 "JsonMappingException while loading network config "
201 + "from file: %s: %s",
202 configFileName,
203 e.getMessage());
204 throw new NetworkConfigException.ErrorConfig(err);
205 } catch (IOException e) {
206 String err = String.format("IOException while loading network config "
207 + "from file: %s %s", configFileName, e.getMessage());
208 throw new NetworkConfigException.ErrorConfig(err);
209 }
210
211 log.info("Network config specifies: {} switches and {} links",
212 (networkConfig.getRestrictSwitches())
213 ? networkConfig.getSwitchConfig().size() : "default allow",
214 (networkConfig.getRestrictLinks())
215 ? networkConfig.getLinkConfig().size() : "default allow");
216 }
217
218 private void parseNetworkConfig() {
219 List<SwitchConfig> swConfList = networkConfig.getSwitchConfig();
220 List<LinkConfig> lkConfList = networkConfig.getLinkConfig();
221 validateSwitchConfig(swConfList);
222 createTypeSpecificSwitchConfig(swConfList);
223 validateLinkConfig(lkConfList);
224 createTypeSpecificLinkConfig(lkConfList);
225 // TODO validate reachability matrix 'names' for configured dpids
226 }
227
228 private void createTypeSpecificSwitchConfig(List<SwitchConfig> swConfList) {
229 for (SwitchConfig swc : swConfList) {
230 nameToDpid.put(swc.getName(), swc.getDpid());
231 String swtype = swc.getType();
232 switch (swtype) {
233 case SEGMENT_ROUTER:
234 SwitchConfig sr = new SegmentRouterConfig(swc);
235 configuredSwitches.put(sr.getDpid(), sr);
236 break;
237 default:
238 throw new NetworkConfigException.UnknownSwitchType(swtype,
239 swc.getName());
240 }
241 }
242 }
243
244 private void createTypeSpecificLinkConfig(List<LinkConfig> lkConfList) {
245 for (LinkConfig lkc : lkConfList) {
246 String lktype = lkc.getType();
247 switch (lktype) {
248 case PKT_LINK:
249 PktLinkConfig pk = new PktLinkConfig(lkc);
250 for (Link lt : pk.getLinkTupleList()) {
251 configuredLinks.put(lt, pk);
252 }
253 break;
254 default:
255 throw new NetworkConfigException.UnknownLinkType(lktype,
256 lkc.getNodeDpid1(), lkc.getNodeDpid2());
257 }
258 }
259 }
260
261 private void validateSwitchConfig(List<SwitchConfig> swConfList) {
262 Set<DeviceId> swDpids = new HashSet<DeviceId>();
263 Set<String> swNames = new HashSet<String>();
264 for (SwitchConfig swc : swConfList) {
265 if (swc.getNodeDpid() == null || swc.getDpid() == null) {
266 throw new NetworkConfigException.DpidNotSpecified(swc.getName());
267 }
268 // ensure both String and DeviceId values of dpid are set
269 if (!swc.getDpid().equals(DeviceId.deviceId(swc.getNodeDpid()))) {
270 throw new NetworkConfigException.SwitchDpidNotConverted(
271 swc.getName());
272 }
273 if (swc.getName() == null) {
274 throw new NetworkConfigException.NameNotSpecified(swc.getDpid());
275 }
276 if (swc.getType() == null) {
277 throw new NetworkConfigException.SwitchTypeNotSpecified(
278 swc.getDpid());
279 }
280 if (!swDpids.add(swc.getDpid())) {
281 throw new NetworkConfigException.DuplicateDpid(swc.getDpid());
282 }
283 if (!swNames.add(swc.getName())) {
284 throw new NetworkConfigException.DuplicateName(swc.getName());
285 }
286 // TODO Add more validations
287 }
288 }
289
290 private void validateLinkConfig(List<LinkConfig> lkConfList) {
291 for (LinkConfig lkc : lkConfList) {
292 if (lkc.getNodeDpid1() == null || lkc.getNodeDpid2() == null) {
293 throw new NetworkConfigException.LinkDpidNotSpecified(
294 lkc.getNodeDpid1(), lkc.getNodeDpid2());
295 }
296 // ensure both String and Long values are set
297 if (!lkc.getDpid1().equals(DeviceId.deviceId(lkc.getNodeDpid1())) ||
298 !lkc.getDpid2().equals(DeviceId.deviceId(lkc.getNodeDpid2()))) {
299 throw new NetworkConfigException.LinkDpidNotConverted(
300 lkc.getNodeDpid1(), lkc.getNodeDpid2());
301 }
302 if (lkc.getType() == null) {
303 throw new NetworkConfigException.LinkTypeNotSpecified(
304 lkc.getNodeDpid1(), lkc.getNodeDpid2());
305 }
306 if (configuredSwitches.get(lkc.getDpid1()) == null) {
307 throw new NetworkConfigException.LinkForUnknownSwitchConfig(
308 lkc.getNodeDpid1());
309 }
310 if (configuredSwitches.get(lkc.getDpid2()) == null) {
311 throw new NetworkConfigException.LinkForUnknownSwitchConfig(
312 lkc.getNodeDpid2());
313 }
314 // TODO add more validations
315 }
316
317 }
318
319 private LinkConfig getConfiguredLink(Link linkTuple) {
320 LinkConfig lkc = null;
321 // first try the unidirectional link with the ports assigned
322 lkc = configuredLinks.get(linkTuple);
323 return lkc;
324 }
325
326
327 /**
328 * Initializes the network configuration manager module by
329 * loading and parsing the network configuration file.
330 */
331 public void init() {
332 loadNetworkConfig();
333 configuredSwitches = new ConcurrentHashMap<DeviceId, SwitchConfig>();
334 configuredLinks = new ConcurrentHashMap<Link, LinkConfig>();
335 nameToDpid = new HashMap<String, DeviceId>();
336 parseNetworkConfig();
337 }
338}