44e4f1c6c185d45c0914ca74f954b99d6439162b
[onosfw.git] /
1 package org.onosproject.segmentrouting.config;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.util.ArrayList;
6 import java.util.HashMap;
7 import java.util.HashSet;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.Set;
11 import java.util.concurrent.ConcurrentHashMap;
12 import java.util.concurrent.ConcurrentMap;
13
14 import org.onosproject.net.DeviceId;
15 import org.onosproject.net.Link;
16 import org.onosproject.segmentrouting.config.NetworkConfig.LinkConfig;
17 import org.onosproject.segmentrouting.config.NetworkConfig.SwitchConfig;
18 import org.slf4j.Logger;
19 import org.slf4j.LoggerFactory;
20
21 import com.fasterxml.jackson.core.JsonParseException;
22 import com.fasterxml.jackson.databind.JsonMappingException;
23 import 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  */
31 public 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 }