blob: d7c0ac461a9571a8513f977844fd0f4db37755e2 [file] [log] [blame]
Saurav Dasfb93c252014-08-18 20:40:13 -07001package net.onrc.onos.core.configmanager;
2
3import java.io.File;
4import java.io.IOException;
5import java.util.ArrayList;
6import java.util.Collection;
7import java.util.Collections;
8import java.util.HashMap;
9import java.util.HashSet;
10import java.util.List;
11import java.util.Map;
12import java.util.Set;
13import java.util.concurrent.ConcurrentHashMap;
14import java.util.concurrent.ConcurrentMap;
15
16import net.floodlightcontroller.core.module.FloodlightModuleContext;
17import net.floodlightcontroller.core.module.FloodlightModuleException;
18import net.floodlightcontroller.core.module.IFloodlightModule;
19import net.floodlightcontroller.core.module.IFloodlightService;
20import net.onrc.onos.core.configmanager.NetworkConfig.LinkConfig;
21import net.onrc.onos.core.configmanager.NetworkConfig.SwitchConfig;
Saurav Dasfb93c252014-08-18 20:40:13 -070022import net.onrc.onos.core.util.Dpid;
23import net.onrc.onos.core.util.LinkTuple;
Jonathan Hart8c802b42014-09-08 15:40:48 -070024import net.onrc.onos.core.util.PortNumber;
Saurav Dasfb93c252014-08-18 20:40:13 -070025
26import org.codehaus.jackson.JsonParseException;
27import org.codehaus.jackson.map.JsonMappingException;
28import org.codehaus.jackson.map.ObjectMapper;
29import org.projectfloodlight.openflow.util.HexString;
30import org.slf4j.Logger;
31import org.slf4j.LoggerFactory;
32
33/**
34 * NetworkConfigManager manages all network configuration for switches, links
35 * and any other state that needs to be configured for correct network
36 * operation.
37 *
38 */
39public class NetworkConfigManager implements IFloodlightModule,
40 INetworkConfigService {
41 protected static final Logger log = LoggerFactory
42 .getLogger(NetworkConfigManager.class);
43 public static final String DEFAULT_NETWORK_CONFIG_FILE =
44 "conf/example-network.conf";
45 /**
46 * JSON Config file needs to use one of the following types for defining the
47 * kind of switch or link it wishes to configure.
48 */
Saurav Dasfc5e3eb2014-09-25 19:05:21 -070049 public static final String SEGMENT_ROUTER = "Router_SR";
50 public static final String ROADM = "Roadm";
51 public static final String OF10SWITCH = "Switch_OF10";
Saurav Dasfb93c252014-08-18 20:40:13 -070052
Saurav Dasfc5e3eb2014-09-25 19:05:21 -070053 public static final String PKT_LINK = "pktLink";
54 public static final String WDM_LINK = "wdmLink";
55 public static final String PKT_OPT_LINK = "pktOptLink";
Saurav Dasfb93c252014-08-18 20:40:13 -070056
57 NetworkConfig networkConfig;
58 private ConcurrentMap<Long, SwitchConfig> configuredSwitches;
59 private ConcurrentMap<LinkTuple, LinkConfig> configuredLinks;
60 private Map<String, Long> nameToDpid;
61
62 // **************
63 // INetworkConfigService
64 // **************
65
66 public SwitchConfigStatus checkSwitchConfig(Dpid dpid) {
67 SwitchConfig swc = configuredSwitches.get(dpid.value());
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
Jonathan Hart8c802b42014-09-08 15:40:48 -0700101 public LinkConfigStatus checkLinkConfig(LinkTuple linkTuple) {
102 LinkConfig lkc = getConfiguredLink(linkTuple);
Saurav Dasfb93c252014-08-18 20:40:13 -0700103 // links are always disallowed if any one of the nodes that make up the
104 // link are disallowed
Jonathan Hart8c802b42014-09-08 15:40:48 -0700105 Dpid linkNode1 = linkTuple.getSrc().getDpid();
Saurav Dasfb93c252014-08-18 20:40:13 -0700106 SwitchConfigStatus scs1 = checkSwitchConfig(linkNode1);
107 if (scs1.getConfigState() == NetworkConfigState.DENY) {
108 return new LinkConfigStatus(NetworkConfigState.DENY, null,
109 "Link-node: " + linkNode1 + " denied by config: " + scs1.getMsg());
110 }
Jonathan Hart8c802b42014-09-08 15:40:48 -0700111 Dpid linkNode2 = linkTuple.getDst().getDpid();
Saurav Dasfb93c252014-08-18 20:40:13 -0700112 SwitchConfigStatus scs2 = checkSwitchConfig(linkNode2);
113 if (scs2.getConfigState() == NetworkConfigState.DENY) {
114 return new LinkConfigStatus(NetworkConfigState.DENY, null,
115 "Link-node: " + linkNode2 + " denied by config: " + scs2.getMsg());
116 }
117 if (networkConfig.getRestrictLinks()) {
118 // default deny behavior
119 if (lkc == null) {
120 // link is not configured - we deny this link
121 return new LinkConfigStatus(NetworkConfigState.DENY, null,
122 "Link not configured, in network denying links by default.");
123 }
124 if (lkc.isAllowed()) {
125 // link is allowed in config, return configured attributes
126 return new LinkConfigStatus(NetworkConfigState.ACCEPT_ADD, lkc);
127 } else {
128 // link has been configured off (administratively down)
129 return new LinkConfigStatus(NetworkConfigState.DENY, null,
130 "Link configured down (allowed=false).");
131 }
132 } else {
133 // default allow behavior
134 if (lkc == null) {
135 // no config to add
136 return new LinkConfigStatus(NetworkConfigState.ACCEPT, null);
137 }
138 if (lkc.isAllowed()) {
139 // link is allowed in config, return configured attributes
140 return new LinkConfigStatus(NetworkConfigState.ACCEPT_ADD, lkc);
141 } else {
142 // link has been configured off (administratively down)
143 return new LinkConfigStatus(NetworkConfigState.DENY, null,
144 "Link configured down (allowed=false).");
145 }
146 }
147
148 }
149
150 @Override
151 public List<SwitchConfig> getConfiguredAllowedSwitches() {
152 List<SwitchConfig> allowed = new ArrayList<SwitchConfig>();
153 for (SwitchConfig swc : configuredSwitches.values()) {
154 if (swc.isAllowed()) {
155 allowed.add(swc);
156 }
157 }
158 return allowed;
159 }
160
161 @Override
162 public List<LinkConfig> getConfiguredAllowedLinks() {
163 List<LinkConfig> allowed = new ArrayList<LinkConfig>();
164 for (LinkConfig lkc : configuredLinks.values()) {
165 if (lkc.isAllowed()) {
166 allowed.add(lkc);
167 }
168 }
169 return allowed;
170 }
171
172 @Override
173 public List<List<String>> getOpticalReachabiltyConfig() {
174 if (networkConfig.getOpticalReachability() != null) {
175 return networkConfig.getOpticalReachability();
176 }
177 return Collections.emptyList();
178 }
179
180 @Override
181 public Dpid getDpidForName(String name) {
182 if (nameToDpid.get(name) != null) {
183 return new Dpid(nameToDpid.get(name));
184 }
185 return null;
186 }
187
188 // **************
189 // Private methods
190 // **************
191
192 private void loadNetworkConfig(FloodlightModuleContext context) {
193 ObjectMapper mapper = new ObjectMapper();
194 networkConfig = new NetworkConfig();
195
196 Map<String, String> configParams = context.getConfigParams(this);
197 String file = configParams.get("networkConfigFile");
198 if (file == null) {
199 // use default file which no-ops
200 log.info("Using default file for network configuration");
201 file = DEFAULT_NETWORK_CONFIG_FILE;
202 } else {
203 log.info("Loading network configuration from " + file);
204 }
205
206 try {
207 networkConfig = mapper.readValue(new File(file), NetworkConfig.class);
208 } catch (JsonParseException e) {
209 String err = String.format("JsonParseException while loading network "
210 + "config from file: %s: %s", file, e.getMessage());
211 throw new NetworkConfigException.ErrorConfig(err);
212 } catch (JsonMappingException e) {
213 String err = String.format(
214 "JsonMappingException while loading network config "
215 + "from file: %s: %s", file, e.getMessage());
216 throw new NetworkConfigException.ErrorConfig(err);
217 } catch (IOException e) {
218 String err = String.format("IOException while loading network config "
219 + "from file: %s %s", file, e.getMessage());
220 throw new NetworkConfigException.ErrorConfig(err);
221 }
222
223 log.info("Network config specifies: {} switches and {} links",
224 (networkConfig.getRestrictSwitches())
225 ? networkConfig.getSwitchConfig().size() : "default allow",
226 (networkConfig.getRestrictLinks())
227 ? networkConfig.getLinkConfig().size() : "default allow");
228 }
229
230 private void parseNetworkConfig() {
231 List<SwitchConfig> swConfList = networkConfig.getSwitchConfig();
232 List<LinkConfig> lkConfList = networkConfig.getLinkConfig();
233 validateSwitchConfig(swConfList);
234 createTypeSpecificSwitchConfig(swConfList);
235 validateLinkConfig(lkConfList);
236 createTypeSpecificLinkConfig(lkConfList);
237 // TODO validate reachability matrix 'names' for configured dpids
238 }
239
240 private void createTypeSpecificSwitchConfig(List<SwitchConfig> swConfList) {
241 for (SwitchConfig swc : swConfList) {
242 nameToDpid.put(swc.getName(), swc.getDpid());
243 String swtype = swc.getType();
244 switch (swtype) {
245 case SEGMENT_ROUTER:
246 SwitchConfig sr = new SegmentRouterConfig(swc);
247 configuredSwitches.put(sr.getDpid(), sr);
248 break;
249 case ROADM:
250 SwitchConfig rd = new RoadmConfig(swc);
251 configuredSwitches.put(rd.getDpid(), rd);
252 break;
253 case OF10SWITCH:
254 SwitchConfig of10 = new SwitchOF10Config(swc);
255 configuredSwitches.put(of10.getDpid(), of10);
256 break;
257 default:
258 throw new NetworkConfigException.UnknownSwitchType(swtype,
259 swc.getName());
260 }
261 }
262 }
263
264 private void createTypeSpecificLinkConfig(List<LinkConfig> lkConfList) {
265 for (LinkConfig lkc : lkConfList) {
266 String lktype = lkc.getType();
267 switch (lktype) {
268 case PKT_LINK:
269 PktLinkConfig pk = new PktLinkConfig(lkc);
270 for (LinkTuple lt : pk.getLinkTupleList()) {
271 configuredLinks.put(lt, pk);
272 }
273 break;
274 case WDM_LINK:
275 WdmLinkConfig wd = new WdmLinkConfig(lkc);
276 for (LinkTuple lt : wd.getLinkTupleList()) {
277 configuredLinks.put(lt, wd);
278 }
279 break;
280 case PKT_OPT_LINK:
281 PktOptLinkConfig po = new PktOptLinkConfig(lkc);
282 for (LinkTuple lt : po.getLinkTupleList()) {
283 configuredLinks.put(lt, po);
284 }
285 break;
286 default:
287 throw new NetworkConfigException.UnknownLinkType(lktype,
288 lkc.getNodeDpid1(), lkc.getNodeDpid2());
289 }
290 }
291 }
292
293 private void validateSwitchConfig(List<SwitchConfig> swConfList) {
294 Set<Long> swDpids = new HashSet<Long>();
295 Set<String> swNames = new HashSet<String>();
296 for (SwitchConfig swc : swConfList) {
297 if (swc.getNodeDpid() == null || swc.getDpid() == 0) {
298 throw new NetworkConfigException.DpidNotSpecified(swc.getName());
299 }
300 // ensure both String and Long values of dpid are set
301 if (swc.getDpid() != HexString.toLong(swc.getNodeDpid())) {
302 throw new NetworkConfigException.SwitchDpidNotConverted(
303 swc.getName());
304 }
305 if (swc.getName() == null) {
306 throw new NetworkConfigException.NameNotSpecified(swc.getDpid());
307 }
308 if (swc.getType() == null) {
309 throw new NetworkConfigException.SwitchTypeNotSpecified(
310 swc.getDpid());
311 }
312 if (!swDpids.add(swc.getDpid())) {
313 throw new NetworkConfigException.DuplicateDpid(swc.getDpid());
314 }
315 if (!swNames.add(swc.getName())) {
316 throw new NetworkConfigException.DuplicateName(swc.getName());
317 }
318 // TODO Add more validations
319 }
320 }
321
322 private void validateLinkConfig(List<LinkConfig> lkConfList) {
323 for (LinkConfig lkc : lkConfList) {
324 if (lkc.getNodeDpid1() == null || lkc.getNodeDpid2() == null) {
325 throw new NetworkConfigException.LinkDpidNotSpecified(
326 lkc.getNodeDpid1(), lkc.getNodeDpid2());
327 }
328 // ensure both String and Long values are set
329 if (lkc.getDpid1() != HexString.toLong(lkc.getNodeDpid1()) ||
330 lkc.getDpid2() != HexString.toLong(lkc.getNodeDpid2())) {
331 throw new NetworkConfigException.LinkDpidNotConverted(
332 lkc.getNodeDpid1(), lkc.getNodeDpid2());
333 }
334 if (lkc.getType() == null) {
335 throw new NetworkConfigException.LinkTypeNotSpecified(
336 lkc.getNodeDpid1(), lkc.getNodeDpid2());
337 }
338 if (configuredSwitches.get(lkc.getDpid1()) == null) {
339 throw new NetworkConfigException.LinkForUnknownSwitchConfig(
340 lkc.getNodeDpid1());
341 }
342 if (configuredSwitches.get(lkc.getDpid2()) == null) {
343 throw new NetworkConfigException.LinkForUnknownSwitchConfig(
344 lkc.getNodeDpid2());
345 }
346 // TODO add more validations
347 }
348
349 }
350
Jonathan Hart8c802b42014-09-08 15:40:48 -0700351 private LinkConfig getConfiguredLink(LinkTuple linkTuple) {
Saurav Dasfb93c252014-08-18 20:40:13 -0700352 LinkConfig lkc = null;
353 // first try the unidirectional link with the ports assigned
Jonathan Hart8c802b42014-09-08 15:40:48 -0700354 lkc = configuredLinks.get(linkTuple);
Saurav Dasfb93c252014-08-18 20:40:13 -0700355 if (lkc == null) {
356 // try without ports, as configuration may be for all links
357 // between the two switches
Jonathan Hart8c802b42014-09-08 15:40:48 -0700358 LinkTuple portlessLink = new LinkTuple(linkTuple.getSrc().getDpid(),
359 PortNumber.uint32(0), linkTuple.getDst().getDpid(),
360 PortNumber.uint32(0));
361
362 lkc = configuredLinks.get(portlessLink);
Saurav Dasfb93c252014-08-18 20:40:13 -0700363 }
364 return lkc;
365 }
366
367
368 // **************
369 // IFloodlightModule
370 // **************
371
372 @Override
373 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
374 Collection<Class<? extends IFloodlightService>> l =
375 new ArrayList<Class<? extends IFloodlightService>>();
376 l.add(INetworkConfigService.class);
377 return l;
378 }
379
380 @Override
381 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
382 Map<Class<? extends IFloodlightService>, IFloodlightService> m =
383 new HashMap<>();
384 m.put(INetworkConfigService.class, this);
385 return m;
386 }
387
388 @Override
389 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
390 // TODO Auto-generated method stub
391 return null;
392 }
393
394 @Override
395 public void init(FloodlightModuleContext context) throws FloodlightModuleException {
396 loadNetworkConfig(context);
397 configuredSwitches = new ConcurrentHashMap<Long, SwitchConfig>();
398 configuredLinks = new ConcurrentHashMap<LinkTuple, LinkConfig>();
399 nameToDpid = new HashMap<String, Long>();
400 }
401
402 @Override
403 public void startUp(FloodlightModuleContext context) throws FloodlightModuleException {
404 parseNetworkConfig();
405 }
406
407}