blob: f508f5d663ab29d2c091d610b6204569b134e887 [file] [log] [blame]
luca8941a312014-09-02 17:51:06 -07001package net.onrc.onos.apps.sdnip;
2
3import java.io.File;
4import java.io.IOException;
5import java.net.InetAddress;
6import java.util.ArrayList;
7import java.util.Collection;
8import java.util.Collections;
9import java.util.HashMap;
10import java.util.HashSet;
11import java.util.Iterator;
12import java.util.Map;
13import java.util.Set;
14
15import net.floodlightcontroller.core.module.FloodlightModuleContext;
16import net.floodlightcontroller.core.module.FloodlightModuleException;
17import net.floodlightcontroller.core.module.IFloodlightModule;
18import net.floodlightcontroller.core.module.IFloodlightService;
19import net.floodlightcontroller.util.MACAddress;
20import net.onrc.onos.core.main.config.IConfigInfoService;
21import net.onrc.onos.core.util.SwitchPort;
22
23import org.apache.commons.configuration.ConfigurationRuntimeException;
24import org.codehaus.jackson.JsonParseException;
25import org.codehaus.jackson.map.JsonMappingException;
26import org.codehaus.jackson.map.ObjectMapper;
27import org.slf4j.Logger;
28import org.slf4j.LoggerFactory;
29
30import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory;
31import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree;
32import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree;
33
34/**
35 * SDN-IP Config Reader provides IConfigInfoService
36 * by reading from an SDN-IP configuration file.
37 * It must be enabled on the nodes within the cluster
38 * not running SDN-IP.
39 * <p/>
40 * TODO: As a long term solution, a module providing
41 * general network configuration to ONOS nodes should be used.
42 */
43public class SdnIpConfigReader implements IFloodlightModule, IConfigInfoService {
44
45 private static final Logger log = LoggerFactory.getLogger(SdnIpConfigReader.class);
46
47 private static final String DEFAULT_CONFIG_FILENAME = "config.json";
48 private String currentConfigFilename = DEFAULT_CONFIG_FILENAME;
49 private Map<String, Interface> interfaces;
50 private Map<InetAddress, BgpPeer> bgpPeers;
51 private MACAddress bgpdMacAddress;
52 private short vlan;
53 private InvertedRadixTree<Interface> interfaceRoutes;
54 private Set<SwitchPort> externalNetworkSwitchPorts;
55
56 /**
57 * Reads the info contained in the configuration file.
58 *
59 * @param configFilename The name of configuration file for SDN-IP application.
60 */
61 private void readConfiguration(String configFilename) {
62 File gatewaysFile = new File(configFilename);
63 ObjectMapper mapper = new ObjectMapper();
64
65 try {
66 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
67 interfaces = new HashMap<>();
68 for (Interface intf : config.getInterfaces()) {
69 interfaces.put(intf.getName(), intf);
70 externalNetworkSwitchPorts.add(new SwitchPort(intf.getDpid(),
71 intf.getPort()));
72 }
73 bgpPeers = new HashMap<>();
74 for (BgpPeer peer : config.getPeers()) {
75 bgpPeers.put(peer.getIpAddress(), peer);
76 }
77 bgpdMacAddress = config.getBgpdMacAddress();
78 vlan = config.getVlan();
79 } catch (JsonParseException | JsonMappingException e) {
80 log.error("Error in JSON file", e);
81 throw new ConfigurationRuntimeException("Error in JSON file", e);
82 } catch (IOException e) {
83 log.error("Error reading JSON file", e);
84 throw new ConfigurationRuntimeException("Error in JSON file", e);
85 }
86
87 // Populate the interface InvertedRadixTree
88 for (Interface intf : interfaces.values()) {
89 Prefix prefix = new Prefix(intf.getIpAddress().getAddress(),
90 intf.getPrefixLength());
91 interfaceRoutes.put(prefix.toBinaryString(), intf);
92 }
93 }
94
95 /**
96 * To find the Interface which has longest matchable IP prefix (sub-network
97 * prefix) to next hop IP address.
98 *
99 * @param address the IP address of next hop router
100 * @return Interface the Interface which has longest matchable IP prefix
101 */
102 private Interface longestInterfacePrefixMatch(InetAddress address) {
103 Prefix prefixToSearchFor = new Prefix(address.getAddress(),
104 Prefix.MAX_PREFIX_LENGTH);
105 Iterator<Interface> it =
106 interfaceRoutes.getValuesForKeysPrefixing(
107 prefixToSearchFor.toBinaryString()).iterator();
108 Interface intf = null;
109 // Find the last prefix, which will be the longest prefix
110 while (it.hasNext()) {
111 intf = it.next();
112 }
113
114 return intf;
115 }
116
117 @Override
118 public boolean isInterfaceAddress(InetAddress address) {
119 Interface intf = longestInterfacePrefixMatch(address);
120 return (intf != null && intf.getIpAddress().equals(address));
121 }
122
123 @Override
124 public boolean inConnectedNetwork(InetAddress address) {
125 Interface intf = longestInterfacePrefixMatch(address);
126 return (intf != null && !intf.getIpAddress().equals(address));
127 }
128
129 @Override
130 public boolean fromExternalNetwork(long inDpid, short inPort) {
131 for (Interface intf : interfaces.values()) {
132 if (intf.getDpid() == inDpid && intf.getPort() == inPort) {
133 return true;
134 }
135 }
136 return false;
137 }
138
139 @Override
140 public Interface getOutgoingInterface(InetAddress dstIpAddress) {
141 return longestInterfacePrefixMatch(dstIpAddress);
142 }
143
144 @Override
145 public boolean hasLayer3Configuration() {
146 return !interfaces.isEmpty();
147 }
148
149 @Override
150 public MACAddress getRouterMacAddress() {
151 return bgpdMacAddress;
152 }
153
154 @Override
155 public short getVlan() {
156 return vlan;
157 }
158
159 @Override
160 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
161 Collection<Class<? extends IFloodlightService>> l = new ArrayList<>();
162 l.add(IConfigInfoService.class);
163 return l;
164 }
165
166 @Override
167 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
168 Map<Class<? extends IFloodlightService>, IFloodlightService> m = new HashMap<>();
169 m.put(IConfigInfoService.class, this);
170 return m;
171 }
172
173 @Override
174 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
175 return null;
176 }
177
178 @Override
179 public void init(FloodlightModuleContext context) throws FloodlightModuleException {
180 interfaceRoutes = new ConcurrentInvertedRadixTree<>(
181 new DefaultByteArrayNodeFactory());
182 externalNetworkSwitchPorts = new HashSet<SwitchPort>();
183 // Reading config values
184 String configFilenameParameter = context.getConfigParams(this).get("configfile");
185 if (configFilenameParameter != null) {
186 currentConfigFilename = configFilenameParameter;
187 }
188 log.debug("Config file set to {}", currentConfigFilename);
189
190 readConfiguration(currentConfigFilename);
191 }
192
193 @Override
194 public void startUp(FloodlightModuleContext context) throws FloodlightModuleException {
195 }
196
197 @Override
198 public Set<SwitchPort> getExternalSwitchPorts() {
199 return Collections.unmodifiableSet(externalNetworkSwitchPorts);
200 }
201}