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