aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/onos/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/config/NetworkConfigManager.java
blob: 44e4f1c6c185d45c0914ca74f954b99d6439162b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
package org.onosproject.segmentrouting.config;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.onosproject.net.DeviceId;
import org.onosproject.net.Link;
import org.onosproject.segmentrouting.config.NetworkConfig.LinkConfig;
import org.onosproject.segmentrouting.config.NetworkConfig.SwitchConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * NetworkConfigManager manages all network configuration for switches, links
 * and any other state that needs to be configured for correct network
 * operation.
 *
 */
public class NetworkConfigManager implements NetworkConfigService {
    protected static final Logger log = LoggerFactory
            .getLogger(NetworkConfigManager.class);
    private static final String CONFIG_DIR = "../config";
    private static final String DEFAULT_CONFIG_FILE = "segmentrouting.conf";
    private final String configFileName = DEFAULT_CONFIG_FILE;
    /**
     * JSON Config file needs to use one of the following types for defining the
     * kind of switch or link it wishes to configure.
     */
    public static final String SEGMENT_ROUTER = "Router_SR";

    public static final String PKT_LINK = "pktLink";

    NetworkConfig networkConfig;
    private ConcurrentMap<DeviceId, SwitchConfig> configuredSwitches;
    private ConcurrentMap<Link, LinkConfig> configuredLinks;
    private Map<String, DeviceId> nameToDpid;

    @Override
    public SwitchConfigStatus checkSwitchConfig(DeviceId dpid) {
        SwitchConfig swc = configuredSwitches.get(dpid);
        if (networkConfig.getRestrictSwitches()) {
            // default deny behavior
            if (swc == null) {
                // switch is not configured - we deny this switch
                return new SwitchConfigStatus(NetworkConfigState.DENY, null,
                        "Switch not configured, in network denying switches by default.");
            }
            if (swc.isAllowed()) {
                // switch is allowed in config, return configured attributes
                return new SwitchConfigStatus(NetworkConfigState.ACCEPT_ADD, swc);
            } else {
                // switch has been configured off (administratively down)
                return new SwitchConfigStatus(NetworkConfigState.DENY, null,
                        "Switch configured down (allowed=false).");
            }
        } else {
            // default allow behavior
            if (swc == null) {
                // no config to add
                return new SwitchConfigStatus(NetworkConfigState.ACCEPT, null);
            }
            if (swc.isAllowed()) {
                // switch is allowed in config, return configured attributes
                return new SwitchConfigStatus(NetworkConfigState.ACCEPT_ADD, swc);
            } else {
                // switch has been configured off (administratively down)
                return new SwitchConfigStatus(NetworkConfigState.DENY, null,
                        "Switch configured down (allowed=false).");
            }
        }

    }

    @Override
    public LinkConfigStatus checkLinkConfig(Link linkTuple) {
        LinkConfig lkc = getConfiguredLink(linkTuple);
        // links are always disallowed if any one of the nodes that make up the
        // link are disallowed
        DeviceId linkNode1 = linkTuple.src().deviceId();
        SwitchConfigStatus scs1 = checkSwitchConfig(linkNode1);
        if (scs1.getConfigState() == NetworkConfigState.DENY) {
            return new LinkConfigStatus(NetworkConfigState.DENY, null,
                    "Link-node: " + linkNode1 + " denied by config: " + scs1.getMsg());
        }
        DeviceId linkNode2 = linkTuple.dst().deviceId();
        SwitchConfigStatus scs2 = checkSwitchConfig(linkNode2);
        if (scs2.getConfigState() == NetworkConfigState.DENY) {
            return new LinkConfigStatus(NetworkConfigState.DENY, null,
                    "Link-node: " + linkNode2 + " denied by config: " + scs2.getMsg());
        }
        if (networkConfig.getRestrictLinks()) {
            // default deny behavior
            if (lkc == null) {
                // link is not configured - we deny this link
                return new LinkConfigStatus(NetworkConfigState.DENY, null,
                        "Link not configured, in network denying links by default.");
            }
            if (lkc.isAllowed()) {
                // link is allowed in config, return configured attributes
                return new LinkConfigStatus(NetworkConfigState.ACCEPT_ADD, lkc);
            } else {
                // link has been configured off (administratively down)
                return new LinkConfigStatus(NetworkConfigState.DENY, null,
                        "Link configured down (allowed=false).");
            }
        } else {
            // default allow behavior
            if (lkc == null) {
                // no config to add
                return new LinkConfigStatus(NetworkConfigState.ACCEPT, null);
            }
            if (lkc.isAllowed()) {
                // link is allowed in config, return configured attributes
                return new LinkConfigStatus(NetworkConfigState.ACCEPT_ADD, lkc);
            } else {
                // link has been configured off (administratively down)
                return new LinkConfigStatus(NetworkConfigState.DENY, null,
                        "Link configured down (allowed=false).");
            }
        }

    }

    @Override
    public List<SwitchConfig> getConfiguredAllowedSwitches() {
        List<SwitchConfig> allowed = new ArrayList<SwitchConfig>();
        for (SwitchConfig swc : configuredSwitches.values()) {
            if (swc.isAllowed()) {
                allowed.add(swc);
            }
        }
        return allowed;
    }

    @Override
    public List<LinkConfig> getConfiguredAllowedLinks() {
        List<LinkConfig> allowed = new ArrayList<LinkConfig>();
        for (LinkConfig lkc : configuredLinks.values()) {
            if (lkc.isAllowed()) {
                allowed.add(lkc);
            }
        }
        return allowed;
    }

    @Override
    public DeviceId getDpidForName(String name) {
        if (nameToDpid.get(name) != null) {
            return nameToDpid.get(name);
        }
        return null;
    }

    // **************
    // Private methods
    // **************

    private void loadNetworkConfig() {
        File configFile = new File(CONFIG_DIR, configFileName);
        ObjectMapper mapper = new ObjectMapper();
        networkConfig = new NetworkConfig();

        try {
            networkConfig = mapper.readValue(configFile,
                                             NetworkConfig.class);
        } catch (JsonParseException e) {
            String err = String.format("JsonParseException while loading network "
                    + "config from file: %s: %s", configFileName,
                    e.getMessage());
            throw new NetworkConfigException.ErrorConfig(err);
        } catch (JsonMappingException e) {
            String err = String.format(
                    "JsonMappingException while loading network config "
                            + "from file: %s: %s",
                            configFileName,
                            e.getMessage());
            throw new NetworkConfigException.ErrorConfig(err);
        } catch (IOException e) {
            String err = String.format("IOException while loading network config "
                    + "from file: %s %s", configFileName, e.getMessage());
            throw new NetworkConfigException.ErrorConfig(err);
        }

        log.info("Network config specifies: {} switches and {} links",
                (networkConfig.getRestrictSwitches())
                        ? networkConfig.getSwitchConfig().size() : "default allow",
                        (networkConfig.getRestrictLinks())
                        ? networkConfig.getLinkConfig().size() : "default allow");
    }

    private void parseNetworkConfig() {
        List<SwitchConfig> swConfList = networkConfig.getSwitchConfig();
        List<LinkConfig> lkConfList = networkConfig.getLinkConfig();
        validateSwitchConfig(swConfList);
        createTypeSpecificSwitchConfig(swConfList);
        validateLinkConfig(lkConfList);
        createTypeSpecificLinkConfig(lkConfList);
        // TODO validate reachability matrix 'names' for configured dpids
    }

    private void createTypeSpecificSwitchConfig(List<SwitchConfig> swConfList) {
        for (SwitchConfig swc : swConfList) {
            nameToDpid.put(swc.getName(), swc.getDpid());
            String swtype = swc.getType();
            switch (swtype) {
            case SEGMENT_ROUTER:
                SwitchConfig sr = new SegmentRouterConfig(swc);
                configuredSwitches.put(sr.getDpid(), sr);
                break;
            default:
                throw new NetworkConfigException.UnknownSwitchType(swtype,
                        swc.getName());
            }
        }
    }

    private void createTypeSpecificLinkConfig(List<LinkConfig> lkConfList) {
        for (LinkConfig lkc : lkConfList) {
            String lktype = lkc.getType();
            switch (lktype) {
            case PKT_LINK:
                PktLinkConfig pk = new PktLinkConfig(lkc);
                for (Link lt : pk.getLinkTupleList()) {
                    configuredLinks.put(lt, pk);
                }
                break;
            default:
                throw new NetworkConfigException.UnknownLinkType(lktype,
                        lkc.getNodeDpid1(), lkc.getNodeDpid2());
            }
        }
    }

    private void validateSwitchConfig(List<SwitchConfig> swConfList) {
        Set<DeviceId> swDpids = new HashSet<DeviceId>();
        Set<String> swNames = new HashSet<String>();
        for (SwitchConfig swc : swConfList) {
            if (swc.getNodeDpid() == null || swc.getDpid() == null) {
                throw new NetworkConfigException.DpidNotSpecified(swc.getName());
            }
            // ensure both String and DeviceId values of dpid are set
            if (!swc.getDpid().equals(DeviceId.deviceId(swc.getNodeDpid()))) {
                throw new NetworkConfigException.SwitchDpidNotConverted(
                        swc.getName());
            }
            if (swc.getName() == null) {
                throw new NetworkConfigException.NameNotSpecified(swc.getDpid());
            }
            if (swc.getType() == null) {
                throw new NetworkConfigException.SwitchTypeNotSpecified(
                        swc.getDpid());
            }
            if (!swDpids.add(swc.getDpid())) {
                throw new NetworkConfigException.DuplicateDpid(swc.getDpid());
            }
            if (!swNames.add(swc.getName())) {
                throw new NetworkConfigException.DuplicateName(swc.getName());
            }
            // TODO Add more validations
        }
    }

    private void validateLinkConfig(List<LinkConfig> lkConfList) {
        for (LinkConfig lkc : lkConfList) {
            if (lkc.getNodeDpid1() == null || lkc.getNodeDpid2() == null) {
                throw new NetworkConfigException.LinkDpidNotSpecified(
                        lkc.getNodeDpid1(), lkc.getNodeDpid2());
            }
            // ensure both String and Long values are set
            if (!lkc.getDpid1().equals(DeviceId.deviceId(lkc.getNodeDpid1())) ||
                    !lkc.getDpid2().equals(DeviceId.deviceId(lkc.getNodeDpid2()))) {
                throw new NetworkConfigException.LinkDpidNotConverted(
                        lkc.getNodeDpid1(), lkc.getNodeDpid2());
            }
            if (lkc.getType() == null) {
                throw new NetworkConfigException.LinkTypeNotSpecified(
                        lkc.getNodeDpid1(), lkc.getNodeDpid2());
            }
            if (configuredSwitches.get(lkc.getDpid1()) == null) {
                throw new NetworkConfigException.LinkForUnknownSwitchConfig(
                        lkc.getNodeDpid1());
            }
            if (configuredSwitches.get(lkc.getDpid2()) == null) {
                throw new NetworkConfigException.LinkForUnknownSwitchConfig(
                        lkc.getNodeDpid2());
            }
            // TODO add more validations
        }

    }

    private LinkConfig getConfiguredLink(Link linkTuple) {
        LinkConfig lkc = null;
        // first try the unidirectional link with the ports assigned
        lkc = configuredLinks.get(linkTuple);
        return lkc;
    }


    /**
     * Initializes the network configuration manager module by
     * loading and parsing the network configuration file.
     */
    public void init() {
        loadNetworkConfig();
        configuredSwitches = new ConcurrentHashMap<DeviceId, SwitchConfig>();
        configuredLinks = new ConcurrentHashMap<Link, LinkConfig>();
        nameToDpid = new HashMap<String, DeviceId>();
        parseNetworkConfig();
    }
}