blob: 5e2cb05bdc93096493e28d3a0902f27e24539378 [file] [log] [blame]
HIGUCHI Yutaea60e5f2013-06-12 11:10:21 -07001package net.onrc.onos.ofcontroller.bgproute;
pingping-lina2cbfad2013-03-07 08:39:21 +08002
Jonathan Hartd1f23252013-06-13 15:17:05 +12003import java.io.File;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -07004import java.io.IOException;
5import java.net.InetAddress;
pingping-lina2cbfad2013-03-07 08:39:21 +08006import java.util.ArrayList;
Jonathan Hart61ba9372013-05-19 20:10:29 -07007import java.util.Collection;
pingping-lina2cbfad2013-03-07 08:39:21 +08008import java.util.HashMap;
Jonathan Hart98957bf2013-07-01 14:49:24 +12009import java.util.Iterator;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070010import java.util.List;
Jonathan Hart61ba9372013-05-19 20:10:29 -070011import java.util.Map;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120012import java.util.Set;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120013import java.util.concurrent.BlockingQueue;
14import java.util.concurrent.ExecutorService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120015import java.util.concurrent.Executors;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120016import java.util.concurrent.LinkedBlockingQueue;
Jonathan Hart98957bf2013-07-01 14:49:24 +120017import java.util.concurrent.ScheduledExecutorService;
18import java.util.concurrent.TimeUnit;
pingping-lina2cbfad2013-03-07 08:39:21 +080019
Jonathan Hart61ba9372013-05-19 20:10:29 -070020import net.floodlightcontroller.core.IFloodlightProviderService;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070021import net.floodlightcontroller.core.IOFSwitch;
Jonathan Hart64c0b202013-08-20 15:45:07 +120022import net.floodlightcontroller.core.IOFSwitchListener;
pingping-lina2cbfad2013-03-07 08:39:21 +080023import net.floodlightcontroller.core.module.FloodlightModuleContext;
24import net.floodlightcontroller.core.module.FloodlightModuleException;
25import net.floodlightcontroller.core.module.IFloodlightModule;
26import net.floodlightcontroller.core.module.IFloodlightService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120027import net.floodlightcontroller.core.util.SingletonTask;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070028import net.floodlightcontroller.packet.Ethernet;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120029import net.floodlightcontroller.packet.IPv4;
pingping-lina2cbfad2013-03-07 08:39:21 +080030import net.floodlightcontroller.restserver.IRestApiService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120031import net.floodlightcontroller.routing.Link;
pingping-lina2cbfad2013-03-07 08:39:21 +080032import net.floodlightcontroller.topology.ITopologyListener;
33import net.floodlightcontroller.topology.ITopologyService;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120034import net.floodlightcontroller.util.MACAddress;
Jonathan Hart0ee0f022013-08-03 22:21:54 +120035import net.onrc.onos.ofcontroller.bgproute.RibUpdate.Operation;
Jonathan Hart98957bf2013-07-01 14:49:24 +120036import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoLinkService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120037import net.onrc.onos.ofcontroller.core.internal.TopoLinkServiceImpl;
HIGUCHI Yutaa56fbde2013-06-17 14:26:05 -070038import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery;
39import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery.LDUpdate;
Jonathan Harte7694532013-09-12 12:34:46 +120040import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscoveryService;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120041import net.onrc.onos.ofcontroller.proxyarp.IArpRequester;
Jonathan Hart5afde492013-10-01 12:30:53 +130042import net.onrc.onos.ofcontroller.proxyarp.IProxyArpService;
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -070043import net.onrc.onos.ofcontroller.topology.ITopologyNetService;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070044import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavove1b37bc2013-10-16 03:57:06 -070045import net.onrc.onos.ofcontroller.topology.TopologyManager;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070046import net.onrc.onos.ofcontroller.util.DataPath;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120047import net.onrc.onos.ofcontroller.util.Dpid;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070048import net.onrc.onos.ofcontroller.util.FlowEntry;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070049import net.onrc.onos.ofcontroller.util.Port;
50import net.onrc.onos.ofcontroller.util.SwitchPort;
pingping-line2a09ca2013-03-23 09:33:58 +080051import net.sf.json.JSONArray;
52import net.sf.json.JSONObject;
53import net.sf.json.JSONSerializer;
pingping-lina2cbfad2013-03-07 08:39:21 +080054
Jonathan Hartd1f23252013-06-13 15:17:05 +120055import org.codehaus.jackson.JsonParseException;
56import org.codehaus.jackson.map.JsonMappingException;
57import org.codehaus.jackson.map.ObjectMapper;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070058import org.openflow.protocol.OFFlowMod;
59import org.openflow.protocol.OFMatch;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070060import org.openflow.protocol.OFPacketOut;
Jonathan Hart9575cb62013-07-05 13:43:49 +120061import org.openflow.protocol.OFPort;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070062import org.openflow.protocol.OFType;
63import org.openflow.protocol.action.OFAction;
64import org.openflow.protocol.action.OFActionDataLayerDestination;
65import org.openflow.protocol.action.OFActionOutput;
Jonathan Hart1236a9b2013-06-18 22:10:05 +120066import org.openflow.util.HexString;
pingping-lina2cbfad2013-03-07 08:39:21 +080067import org.slf4j.Logger;
68import org.slf4j.LoggerFactory;
69
Jonathan Hart4dfc3652013-08-02 20:22:36 +120070import com.google.common.collect.HashMultimap;
Jonathan Hart0ee0f022013-08-03 22:21:54 +120071import com.google.common.collect.Multimap;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120072import com.google.common.collect.Multimaps;
73import com.google.common.collect.SetMultimap;
Jonathan Hart309889c2013-08-13 23:26:24 +120074import com.google.common.net.InetAddresses;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120075import com.google.common.util.concurrent.ThreadFactoryBuilder;
76
Jonathan Hart1236a9b2013-06-18 22:10:05 +120077public class BgpRoute implements IFloodlightModule, IBgpRouteService,
Jonathan Hart64c0b202013-08-20 15:45:07 +120078 ITopologyListener, IArpRequester,
Jonathan Harta8887642013-10-28 13:46:54 -070079 IOFSwitchListener, IConfigInfoService,
Jonathan Hart5afde492013-10-01 12:30:53 +130080 IProxyArpService {
pingping-lina2cbfad2013-03-07 08:39:21 +080081
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -070082 private final static Logger log = LoggerFactory.getLogger(BgpRoute.class);
pingping-lina2cbfad2013-03-07 08:39:21 +080083
Jonathan Hartf247ee72013-10-18 18:57:28 -070084 private IFloodlightProviderService floodlightProvider;
Jonathan Hart3a326122013-10-21 11:51:13 -070085 private ITopologyService topologyService;
Jonathan Hartf247ee72013-10-18 18:57:28 -070086 private ITopologyNetService topologyNetService;
87 private ILinkDiscoveryService linkDiscoveryService;
88 private IRestApiService restApi;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070089
Jonathan Harta8887642013-10-28 13:46:54 -070090 private IProxyArpService proxyArp;
Jonathan Hartc7ca35d2013-06-25 20:54:25 +120091
Jonathan Hartf247ee72013-10-18 18:57:28 -070092 private IPatriciaTrie<RibEntry> ptree;
93 private IPatriciaTrie<Interface> interfacePtrie;
94 private BlockingQueue<RibUpdate> ribUpdates;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120095
Jonathan Hartf247ee72013-10-18 18:57:28 -070096 private String bgpdRestIp;
97 private String routerId;
98 private String configFilename = "config.json";
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070099
100 //We need to identify our flows somehow. But like it says in LearningSwitch.java,
101 //the controller/OS should hand out cookie IDs to prevent conflicts.
Jonathan Hartf247ee72013-10-18 18:57:28 -0700102 private final long APP_COOKIE = 0xa0000000000000L;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700103 //Cookie for flows that do L2 forwarding within SDN domain to egress routers
Jonathan Hartf247ee72013-10-18 18:57:28 -0700104 private final long L2_FWD_COOKIE = APP_COOKIE + 1;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700105 //Cookie for flows in ingress switches that rewrite the MAC address
Jonathan Hartf247ee72013-10-18 18:57:28 -0700106 private final long MAC_RW_COOKIE = APP_COOKIE + 2;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200107 //Cookie for flows that setup BGP paths
Jonathan Hartf247ee72013-10-18 18:57:28 -0700108 private final long BGP_COOKIE = APP_COOKIE + 3;
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200109 //Forwarding uses priority 0, and the mac rewrite entries in ingress switches
110 //need to be higher priority than this otherwise the rewrite may not get done
Jonathan Hartf247ee72013-10-18 18:57:28 -0700111 private final short SDNIP_PRIORITY = 10;
112 private final short ARP_PRIORITY = 20;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700113
Jonathan Hartf247ee72013-10-18 18:57:28 -0700114 private final short BGP_PORT = 179;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200115
Jonathan Hartf247ee72013-10-18 18:57:28 -0700116 private final int TOPO_DETECTION_WAIT = 2; //seconds
Jonathan Hart98957bf2013-07-01 14:49:24 +1200117
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200118 //Configuration stuff
Jonathan Hartf247ee72013-10-18 18:57:28 -0700119 private List<String> switches;
120 private Map<String, Interface> interfaces;
121 private Map<InetAddress, BgpPeer> bgpPeers;
122 private SwitchPort bgpdAttachmentPoint;
123 private MACAddress bgpdMacAddress;
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700124 private short vlan;
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200125
126 //True when all switches have connected
Jonathan Hartf247ee72013-10-18 18:57:28 -0700127 private volatile boolean switchesConnected = false;
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200128 //True when we have a full mesh of shortest paths between gateways
Jonathan Hartf247ee72013-10-18 18:57:28 -0700129 private volatile boolean topologyReady = false;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200130
Jonathan Hartf247ee72013-10-18 18:57:28 -0700131 private ArrayList<LDUpdate> linkUpdates;
132 private SingletonTask topologyChangeDetectorTask;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200133
Jonathan Hartf247ee72013-10-18 18:57:28 -0700134 private SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
Jonathan Hart309889c2013-08-13 23:26:24 +1200135
Jonathan Hartf247ee72013-10-18 18:57:28 -0700136 private Map<InetAddress, Path> pathsWaitingOnArp;
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200137
Jonathan Hartf247ee72013-10-18 18:57:28 -0700138 private ExecutorService bgpUpdatesExecutor;
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200139
Jonathan Hartf247ee72013-10-18 18:57:28 -0700140 private Map<InetAddress, Path> pushedPaths;
141 private Map<Prefix, Path> prefixToPath;
142 private Multimap<Prefix, PushedFlowMod> pushedFlows;
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200143
Jonathan Hart1912afc2013-10-11 12:02:44 +1300144 private FlowCache flowCache;
145
Jonathan Hart3a326122013-10-21 11:51:13 -0700146 private volatile Topology topology = null;
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200147
Jonathan Hartf247ee72013-10-18 18:57:28 -0700148 private class TopologyChangeDetector implements Runnable {
Jonathan Hart98957bf2013-07-01 14:49:24 +1200149 @Override
150 public void run() {
151 log.debug("Running topology change detection task");
152 synchronized (linkUpdates) {
Jonathan Hartc824ad02013-07-03 15:58:45 +1200153 //This is the model the REST API uses to retrieve network graph info
Jonathan Hart98957bf2013-07-01 14:49:24 +1200154 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
155
156 List<Link> activeLinks = topoLinkService.getActiveLinks();
Jonathan Hart98957bf2013-07-01 14:49:24 +1200157
158 Iterator<LDUpdate> it = linkUpdates.iterator();
159 while (it.hasNext()){
160 LDUpdate ldu = it.next();
161 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
162 ldu.getDst(), ldu.getDstPort());
163
164 if (activeLinks.contains(l)){
Jonathan Hart98957bf2013-07-01 14:49:24 +1200165 it.remove();
166 }
167 }
168 }
169
Jonathan Hart64c0b202013-08-20 15:45:07 +1200170 if (!topologyReady) {
171 if (linkUpdates.isEmpty()){
172 //All updates have been seen in network map.
173 //We can check if topology is ready
174 log.debug("No known changes outstanding. Checking topology now");
175 checkStatus();
176 }
177 else {
178 //We know of some link updates that haven't propagated to the database yet
179 log.debug("Some changes not found in network map - {} links missing", linkUpdates.size());
180 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
181 }
Jonathan Hart98957bf2013-07-01 14:49:24 +1200182 }
183 }
184 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700185
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700186 private void readConfiguration(String configFilename){
187 File gatewaysFile = new File(configFilename);
Jonathan Hartd1f23252013-06-13 15:17:05 +1200188 ObjectMapper mapper = new ObjectMapper();
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700189
Jonathan Hartd1f23252013-06-13 15:17:05 +1200190 try {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200191 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
192
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200193 switches = config.getSwitches();
Jonathan Hart9575cb62013-07-05 13:43:49 +1200194 interfaces = new HashMap<String, Interface>();
195 for (Interface intf : config.getInterfaces()){
196 interfaces.put(intf.getName(), intf);
197 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200198 bgpPeers = new HashMap<InetAddress, BgpPeer>();
199 for (BgpPeer peer : config.getPeers()){
200 bgpPeers.put(peer.getIpAddress(), peer);
201 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200202
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200203 bgpdAttachmentPoint = new SwitchPort(
204 new Dpid(config.getBgpdAttachmentDpid()),
205 new Port(config.getBgpdAttachmentPort()));
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200206
Jonathan Hart2f790d22013-08-15 14:01:24 +1200207 bgpdMacAddress = config.getBgpdMacAddress();
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700208 vlan = config.getVlan();
Jonathan Hartd1f23252013-06-13 15:17:05 +1200209 } catch (JsonParseException e) {
210 log.error("Error in JSON file", e);
211 System.exit(1);
212 } catch (JsonMappingException e) {
213 log.error("Error in JSON file", e);
214 System.exit(1);
215 } catch (IOException e) {
216 log.error("Error reading JSON file", e);
217 System.exit(1);
218 }
Jonathan Hartabf10222013-08-13 10:19:34 +1200219
220 //Populate the interface Patricia Trie
221 for (Interface intf : interfaces.values()) {
222 Prefix prefix = new Prefix(intf.getIpAddress().getAddress(), intf.getPrefixLength());
223 interfacePtrie.put(prefix, intf);
224 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700225 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800226
227 @Override
228 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700229 Collection<Class<? extends IFloodlightService>> l
230 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800231 l.add(IBgpRouteService.class);
Jonathan Harta8887642013-10-28 13:46:54 -0700232 l.add(IConfigInfoService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800233 return l;
234 }
235
236 @Override
237 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700238 Map<Class<? extends IFloodlightService>, IFloodlightService> m
239 = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
pingping-line2a09ca2013-03-23 09:33:58 +0800240 m.put(IBgpRouteService.class, this);
Jonathan Harta8887642013-10-28 13:46:54 -0700241 m.put(IConfigInfoService.class, this);
pingping-lina2cbfad2013-03-07 08:39:21 +0800242 return m;
243 }
244
pingping-lina2cbfad2013-03-07 08:39:21 +0800245 @Override
246 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700247 Collection<Class<? extends IFloodlightService>> l
248 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800249 l.add(IFloodlightProviderService.class);
250 l.add(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700251 l.add(IRestApiService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800252 return l;
253 }
254
255 @Override
256 public void init(FloodlightModuleContext context)
257 throws FloodlightModuleException {
258
Jonathan Hart29b972d2013-08-12 23:43:51 +1200259 ptree = new PatriciaTrie<RibEntry>(32);
Jonathan Hartabf10222013-08-13 10:19:34 +1200260 interfacePtrie = new PatriciaTrie<Interface>(32);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200261
262 ribUpdates = new LinkedBlockingQueue<RibUpdate>();
Jonathan Hartc824ad02013-07-03 15:58:45 +1200263
pingping-lina2cbfad2013-03-07 08:39:21 +0800264 // Register floodlight provider and REST handler.
265 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700266 topologyService = context.getServiceImpl(ITopologyService.class);
Jonathan Harte7694532013-09-12 12:34:46 +1200267 linkDiscoveryService = context.getServiceImpl(ILinkDiscoveryService.class);
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200268 restApi = context.getServiceImpl(IRestApiService.class);
269
270 //TODO We'll initialise this here for now, but it should really be done as
271 //part of the controller core
Jonathan Harta8887642013-10-28 13:46:54 -0700272 //proxyArp = new ProxyArpManager(floodlightProvider, topologyService, this, restApi);
273 //proxyArp = new ProxyArpManager();
274 proxyArp = context.getServiceImpl(IProxyArpService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800275
Jonathan Hart98957bf2013-07-01 14:49:24 +1200276 linkUpdates = new ArrayList<LDUpdate>();
277 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
278 topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700279
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -0700280 topologyNetService = new TopologyManager("");
Jonathan Hart98957bf2013-07-01 14:49:24 +1200281
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200282 pathsWaitingOnArp = new HashMap<InetAddress, Path>();
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200283 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
284 HashMultimap.<InetAddress, RibUpdate>create());
285
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200286 pushedPaths = new HashMap<InetAddress, Path>();
287 prefixToPath = new HashMap<Prefix, Path>();
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200288 pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
289
Jonathan Hart1912afc2013-10-11 12:02:44 +1300290 flowCache = new FlowCache(floodlightProvider);
291
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200292 bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
293 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
294
Jonathan Hart61ba9372013-05-19 20:10:29 -0700295 //Read in config values
296 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
297 if (bgpdRestIp == null){
298 log.error("BgpdRestIp property not found in config file");
299 System.exit(1);
300 }
301 else {
302 log.info("BgpdRestIp set to {}", bgpdRestIp);
303 }
304
305 routerId = context.getConfigParams(this).get("RouterId");
306 if (routerId == null){
307 log.error("RouterId property not found in config file");
308 System.exit(1);
309 }
310 else {
311 log.info("RouterId set to {}", routerId);
312 }
Jonathan Hartd1f23252013-06-13 15:17:05 +1200313
Jonathan Hart9575cb62013-07-05 13:43:49 +1200314 String configFilenameParameter = context.getConfigParams(this).get("configfile");
315 if (configFilenameParameter != null){
316 configFilename = configFilenameParameter;
317 }
318 log.debug("Config file set to {}", configFilename);
319
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700320 readConfiguration(configFilename);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200321 }
322
323 @Override
324 public void startUp(FloodlightModuleContext context) {
325 restApi.addRestletRoutable(new BgpRouteWebRoutable());
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700326 topologyService.addListener(this);
Jonathan Hart64c0b202013-08-20 15:45:07 +1200327 floodlightProvider.addOFSwitchListener(this);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200328
Jonathan Harta8887642013-10-28 13:46:54 -0700329 //proxyArp.startUp(vlan);
Jonathan Hart2f790d22013-08-15 14:01:24 +1200330
Jonathan Harta8887642013-10-28 13:46:54 -0700331 //floodlightProvider.addOFMessageListener(OFType.PACKET_IN, proxyArp);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200332
333 //Retrieve the RIB from BGPd during startup
334 retrieveRib();
pingping-lina2cbfad2013-03-07 08:39:21 +0800335 }
336
Jonathan Hart29b972d2013-08-12 23:43:51 +1200337 public IPatriciaTrie<RibEntry> getPtree() {
pingping-lina2cbfad2013-03-07 08:39:21 +0800338 return ptree;
339 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700340
341 public void clearPtree() {
Jonathan Hart29b972d2013-08-12 23:43:51 +1200342 ptree = new PatriciaTrie<RibEntry>(32);
pingping-line2a09ca2013-03-23 09:33:58 +0800343 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700344
pingping-line2a09ca2013-03-23 09:33:58 +0800345 public String getBGPdRestIp() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700346 return bgpdRestIp;
pingping-line2a09ca2013-03-23 09:33:58 +0800347 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700348
pingping-line2a09ca2013-03-23 09:33:58 +0800349 public String getRouterId() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700350 return routerId;
pingping-line2a09ca2013-03-23 09:33:58 +0800351 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800352
Jonathan Hart61ba9372013-05-19 20:10:29 -0700353 private void retrieveRib(){
354 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
355 String response = RestClient.get(url);
356
357 if (response.equals("")){
358 return;
359 }
360
361 response = response.replaceAll("\"", "'");
362 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
363 JSONArray rib_json_array = jsonObj.getJSONArray("rib");
364 String router_id = jsonObj.getString("router-id");
365
366 int size = rib_json_array.size();
367
368 log.info("Retrived RIB of {} entries from BGPd", size);
369
370 for (int j = 0; j < size; j++) {
371 JSONObject second_json_object = rib_json_array.getJSONObject(j);
372 String prefix = second_json_object.getString("prefix");
373 String nexthop = second_json_object.getString("nexthop");
374
375 //insert each rib entry into the local rib;
376 String[] substring = prefix.split("/");
377 String prefix1 = substring[0];
378 String mask1 = substring[1];
379
380 Prefix p;
381 try {
382 p = new Prefix(prefix1, Integer.valueOf(mask1));
383 } catch (NumberFormatException e) {
384 log.warn("Wrong mask format in RIB JSON: {}", mask1);
385 continue;
Jonathan Hart32e18222013-08-07 22:05:42 +1200386 } catch (IllegalArgumentException e1) {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700387 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
388 continue;
389 }
390
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200391 RibEntry rib = new RibEntry(router_id, nexthop);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200392
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200393 try {
394 ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
395 } catch (InterruptedException e) {
396 log.debug("Interrupted while pushing onto update queue");
397 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700398 }
399 }
400
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200401 @Override
402 public void newRibUpdate(RibUpdate update) {
Jonathan Hart9ea31212013-08-12 21:40:34 +1200403 try {
404 ribUpdates.put(update);
405 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200406 log.debug("Interrupted while putting on ribUpdates queue", e);
407 Thread.currentThread().interrupt();
Jonathan Hart9ea31212013-08-12 21:40:34 +1200408 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200409 }
410
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200411 public synchronized void processRibAdd(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200412 Prefix prefix = update.getPrefix();
413
Jonathan Hart9ea31212013-08-12 21:40:34 +1200414 log.debug("Processing prefix add {}", prefix);
415
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200416 RibEntry rib = ptree.put(prefix, update.getRibEntry());
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200417
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200418 if (rib != null && !rib.equals(update.getRibEntry())) {
Jonathan Hart2f740782013-08-04 00:49:21 +1200419 //There was an existing nexthop for this prefix. This update supersedes that,
420 //so we need to remove the old flows for this prefix from the switches
Jonathan Hart309889c2013-08-13 23:26:24 +1200421 _processDeletePrefix(prefix, rib);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200422 }
Jonathan Hart2f740782013-08-04 00:49:21 +1200423
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200424 if (update.getRibEntry().getNextHop().equals(
425 InetAddresses.forString("0.0.0.0"))) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200426 //Route originated by SDN domain
427 //We don't handle these at the moment
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200428 log.debug("Own route {} to {}", prefix,
429 update.getRibEntry().getNextHop().getHostAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200430 return;
431 }
432
433 _processRibAdd(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200434 }
435
Jonathan Hart309889c2013-08-13 23:26:24 +1200436 private void _processRibAdd(RibUpdate update) {
437 Prefix prefix = update.getPrefix();
438 RibEntry rib = update.getRibEntry();
439
440 InetAddress dstIpAddress = rib.getNextHop();
441
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200442 //See if we know the MAC address of the next hop
Jonathan Hartabad6a52013-09-30 18:17:21 +1300443 MACAddress nextHopMacAddress = proxyArp.getMacAddress(rib.getNextHop());
Jonathan Hart309889c2013-08-13 23:26:24 +1200444
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200445 //Find the attachment point (egress interface) of the next hop
446 Interface egressInterface = null;
Jonathan Hart309889c2013-08-13 23:26:24 +1200447 if (bgpPeers.containsKey(dstIpAddress)) {
448 //Route to a peer
449 log.debug("Route to peer {}", dstIpAddress);
450 BgpPeer peer = bgpPeers.get(dstIpAddress);
451 egressInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart309889c2013-08-13 23:26:24 +1200452 }
453 else {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200454 //Route to non-peer
Jonathan Hart309889c2013-08-13 23:26:24 +1200455 log.debug("Route to non-peer {}", dstIpAddress);
456 egressInterface = interfacePtrie.match(
457 new Prefix(dstIpAddress.getAddress(), 32));
458 if (egressInterface == null) {
459 log.warn("No outgoing interface found for {}", dstIpAddress.getHostAddress());
460 return;
461 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200462 }
463
464 if (nextHopMacAddress == null) {
465 prefixesWaitingOnArp.put(dstIpAddress,
466 new RibUpdate(Operation.UPDATE, prefix, rib));
467 proxyArp.sendArpRequest(dstIpAddress, this, true);
468 return;
469 }
470 else {
471 if (!bgpPeers.containsKey(dstIpAddress)) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200472 //If the prefix is for a non-peer we need to ensure there's a path,
473 //and push one if there isn't.
474 Path path = pushedPaths.get(dstIpAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200475 if (path == null) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200476 path = new Path(egressInterface, dstIpAddress);
Jonathan Hartabad6a52013-09-30 18:17:21 +1300477 calculateAndPushPath(path, nextHopMacAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200478 pushedPaths.put(dstIpAddress, path);
479 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200480
481 path.incrementUsers();
482 prefixToPath.put(prefix, path);
483 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200484
485 //For all prefixes we need to add the first-hop mac-rewriting flows
Jonathan Hart309889c2013-08-13 23:26:24 +1200486 addPrefixFlows(prefix, egressInterface, nextHopMacAddress);
487 }
488 }
489
Jonathan Hartabad6a52013-09-30 18:17:21 +1300490 private void addPrefixFlows(Prefix prefix, Interface egressInterface, MACAddress nextHopMacAddress) {
Jonathan Harte4c98692013-10-18 17:40:03 -0700491 log.debug("Adding flows for prefix {}, next hop mac {}",
Jonathan Hartabad6a52013-09-30 18:17:21 +1300492 prefix, nextHopMacAddress);
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200493
494 //We only need one flow mod per switch, so pick one interface on each switch
495 Map<Long, Interface> srcInterfaces = new HashMap<Long, Interface>();
496 for (Interface intf : interfaces.values()) {
497 if (!srcInterfaces.containsKey(intf.getDpid())
Jonathan Hart45107222013-10-22 17:35:04 -0700498 && !intf.equals(egressInterface)) {
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200499 srcInterfaces.put(intf.getDpid(), intf);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200500 }
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200501 }
502
503 //Add a flow to rewrite mac for this prefix to all other border switches
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200504 for (Interface srcInterface : srcInterfaces.values()) {
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200505 DataPath shortestPath;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700506 if (topology == null) {
507 shortestPath = topologyNetService.getDatabaseShortestPath(
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200508 srcInterface.getSwitchPort(),
509 egressInterface.getSwitchPort());
510 }
511 else {
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700512 shortestPath = topologyNetService.getTopologyShortestPath(
513 topology, srcInterface.getSwitchPort(),
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200514 egressInterface.getSwitchPort());
515 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200516
517 if (shortestPath == null){
518 log.debug("Shortest path between {} and {} not found",
519 srcInterface.getSwitchPort(),
520 egressInterface.getSwitchPort());
521 return; // just quit here?
522 }
523
524 //Set up the flow mod
525 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
526 .getMessage(OFType.FLOW_MOD);
527
528 fm.setIdleTimeout((short)0)
529 .setHardTimeout((short)0)
530 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
531 .setCookie(MAC_RW_COOKIE)
532 .setCommand(OFFlowMod.OFPFC_ADD)
533 .setPriority(SDNIP_PRIORITY)
534 .setLengthU(OFFlowMod.MINIMUM_LENGTH
535 + OFActionDataLayerDestination.MINIMUM_LENGTH
536 + OFActionOutput.MINIMUM_LENGTH);
537
538 OFMatch match = new OFMatch();
539 match.setDataLayerType(Ethernet.TYPE_IPv4);
540 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
541
542 match.setFromCIDR(prefix.toString(), OFMatch.STR_NW_DST);
543 fm.setMatch(match);
544
545 //Set up MAC rewrite action
546 OFActionDataLayerDestination macRewriteAction = new OFActionDataLayerDestination();
Jonathan Hartabad6a52013-09-30 18:17:21 +1300547 macRewriteAction.setDataLayerAddress(nextHopMacAddress.toBytes());
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200548
549 //Set up output action
550 OFActionOutput outputAction = new OFActionOutput();
551 outputAction.setMaxLength((short)0xffff);
552 Port outputPort = shortestPath.flowEntries().get(0).outPort();
553 outputAction.setPort(outputPort.value());
554
555 List<OFAction> actions = new ArrayList<OFAction>();
556 actions.add(macRewriteAction);
557 actions.add(outputAction);
558 fm.setActions(actions);
559
Jonathan Hart1912afc2013-10-11 12:02:44 +1300560 pushedFlows.put(prefix, new PushedFlowMod(srcInterface.getDpid(), fm));
561 flowCache.write(srcInterface.getDpid(), fm);
562
563 /*
564 * XXX Rate limit hack!
565 * This should be solved properly by adding a rate limiting
566 * layer on top of the switches if we know they need it.
567 */
568 try {
Jonathan Hart9971e1c2013-09-17 10:47:40 +1200569 Thread.sleep(1);
Jonathan Hart65139e42013-09-13 16:52:25 +1200570 } catch (InterruptedException e) {
571 // TODO handle this properly
572 log.error("Interrupted", e);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200573 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200574 }
575 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200576
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200577 public synchronized void processRibDelete(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200578 Prefix prefix = update.getPrefix();
579
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200580 if (ptree.remove(prefix, update.getRibEntry())) {
581 /*
582 * Only delete flows if an entry was actually removed from the trie.
583 * If no entry was removed, the <prefix, nexthop> wasn't there so
584 * it's probably already been removed and we don't need to do anything
585 */
Jonathan Hart309889c2013-08-13 23:26:24 +1200586 _processDeletePrefix(prefix, update.getRibEntry());
Jonathan Hart309889c2013-08-13 23:26:24 +1200587 }
588 }
589
590 private void _processDeletePrefix(Prefix prefix, RibEntry ribEntry) {
591 deletePrefixFlows(prefix);
592
593 log.debug("Deleting {} to {}", prefix, ribEntry.getNextHop());
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200594
Jonathan Hart309889c2013-08-13 23:26:24 +1200595 if (!bgpPeers.containsKey(ribEntry.getNextHop())) {
596 log.debug("Getting path for route with non-peer nexthop");
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200597 Path path = prefixToPath.remove(prefix);
Jonathan Hart309889c2013-08-13 23:26:24 +1200598
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200599 if (path != null) {
600 //path could be null if we added to the Ptree but didn't push
601 //flows yet because we were waiting to resolve ARP
Jonathan Hart309889c2013-08-13 23:26:24 +1200602
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200603 path.decrementUsers();
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200604 if (path.getUsers() <= 0 && !path.isPermanent()) {
605 deletePath(path);
606 pushedPaths.remove(path.getDstIpAddress());
607 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200608 }
609 }
610 }
611
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200612 private void deletePrefixFlows(Prefix prefix) {
613 log.debug("Deleting flows for prefix {}", prefix);
614
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200615 Collection<PushedFlowMod> pushedFlowMods
616 = pushedFlows.removeAll(prefix);
617
618 for (PushedFlowMod pfm : pushedFlowMods) {
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200619 if (log.isTraceEnabled()) {
620 log.trace("Pushing a DELETE flow mod to {}, matches prefix {} with mac-rewrite {}",
621 new Object[] {HexString.toHexString(pfm.getDpid()),
622 pfm.getFlowMod().getMatch().getNetworkDestination() +
623 pfm.getFlowMod().getMatch().getNetworkDestinationMaskLen(),
624 HexString.toHexString(((OFActionDataLayerDestination)pfm.getFlowMod().getActions().get(0))
625 .getDataLayerAddress())});
626 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200627
628 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
629 }
630 }
631
632 private void deletePath(Path path) {
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200633 log.debug("Deleting flows for path to {}",
634 path.getDstIpAddress().getHostAddress());
635
Jonathan Hart309889c2013-08-13 23:26:24 +1200636 for (PushedFlowMod pfm : path.getFlowMods()) {
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200637 if (log.isTraceEnabled()) {
638 log.trace("Pushing a DELETE flow mod to {}, dst MAC {}",
639 new Object[] {HexString.toHexString(pfm.getDpid()),
640 HexString.toHexString(pfm.getFlowMod().getMatch().getDataLayerDestination())
641 });
642 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200643
644 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
645 }
646 }
647
648 private void sendDeleteFlowMod(OFFlowMod addFlowMod, long dpid) {
Jonathan Hart1912afc2013-10-11 12:02:44 +1300649 flowCache.delete(dpid, addFlowMod);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200650 }
651
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200652 //TODO test next-hop changes
Jonathan Hart2f740782013-08-04 00:49:21 +1200653 //TODO check delete/add synchronization
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200654
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700655 /*
656 * On startup we need to calculate a full mesh of paths between all gateway
657 * switches
658 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200659 private void setupFullMesh(){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700660 //For each border router, calculate and install a path from every other
661 //border switch to said border router. However, don't install the entry
662 //in to the first hop switch, as we need to install an entry to rewrite
663 //for each prefix received. This will be done later when prefixes have
664 //actually been received.
665
Jonathan Hartc824ad02013-07-03 15:58:45 +1200666 for (BgpPeer peer : bgpPeers.values()) {
667 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200668
Jonathan Hart309889c2013-08-13 23:26:24 +1200669 //We know there's not already a Path here pushed, because this is
670 //called before all other routing
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200671 Path path = new Path(peerInterface, peer.getIpAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200672 path.setPermanent();
673
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200674 //See if we know the MAC address of the peer. If not we can't
675 //do anything until we learn it
Jonathan Hartabad6a52013-09-30 18:17:21 +1300676 MACAddress macAddress = proxyArp.getMacAddress(peer.getIpAddress());
677 if (macAddress == null) {
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200678 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
679 //Put in the pending paths list first
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200680 pathsWaitingOnArp.put(peer.getIpAddress(), path);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700681
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200682 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
683 continue;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700684 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200685
686 //If we know the MAC, lets go ahead and push the paths to this peer
Jonathan Hartabad6a52013-09-30 18:17:21 +1300687 calculateAndPushPath(path, macAddress);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700688 }
689 }
690
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200691 private void calculateAndPushPath(Path path, MACAddress dstMacAddress) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200692 Interface dstInterface = path.getDstInterface();
693
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200694 log.debug("Setting up path to {}, {}", path.getDstIpAddress().getHostAddress(),
695 dstMacAddress);
696
Jonathan Hart309889c2013-08-13 23:26:24 +1200697 List<PushedFlowMod> pushedFlows = new ArrayList<PushedFlowMod>();
698
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200699 for (Interface srcInterface : interfaces.values()) {
Jonathan Hart45107222013-10-22 17:35:04 -0700700 if (dstInterface.equals(srcInterface)){
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200701 continue;
702 }
703
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200704 DataPath shortestPath;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700705 if (topology == null) {
706 shortestPath = topologyNetService.getDatabaseShortestPath(
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200707 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
708 }
709 else {
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700710 shortestPath = topologyNetService.getTopologyShortestPath(topology,
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200711 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
712 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200713
714 if (shortestPath == null){
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200715 log.warn("Shortest path between {} and {} not found",
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200716 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200717 return;
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200718 }
719
Jonathan Hart1912afc2013-10-11 12:02:44 +1300720 List<PushedFlowMod> pushedFlowMods = installPath(shortestPath.flowEntries(), dstMacAddress);
721 pushedFlows.addAll(pushedFlowMods);
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200722 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200723
724 path.setFlowMods(pushedFlows);
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200725 }
726
Jonathan Hart309889c2013-08-13 23:26:24 +1200727 private List<PushedFlowMod> installPath(List<FlowEntry> flowEntries, MACAddress dstMacAddress){
728 List<PushedFlowMod> flowMods = new ArrayList<PushedFlowMod>();
729
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700730 //Set up the flow mod
731 OFFlowMod fm =
732 (OFFlowMod) floodlightProvider.getOFMessageFactory()
733 .getMessage(OFType.FLOW_MOD);
734
735 OFActionOutput action = new OFActionOutput();
736 action.setMaxLength((short)0xffff);
737 List<OFAction> actions = new ArrayList<OFAction>();
738 actions.add(action);
739
740 fm.setIdleTimeout((short)0)
741 .setHardTimeout((short)0)
742 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
743 .setCookie(L2_FWD_COOKIE)
744 .setCommand(OFFlowMod.OFPFC_ADD)
Jonathan Hartbdc87462013-09-24 15:03:23 +1200745 .setPriority(SDNIP_PRIORITY)
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700746 .setActions(actions)
747 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
748
749 //Don't push the first flow entry. We need to push entries in the
750 //first switch based on IP prefix which we don't know yet.
751 for (int i = 1; i < flowEntries.size(); i++){
752 FlowEntry flowEntry = flowEntries.get(i);
753
754 OFMatch match = new OFMatch();
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200755 match.setDataLayerDestination(dstMacAddress.toBytes());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700756 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
757 ((OFActionOutput) fm.getActions().get(0)).setPort(flowEntry.outPort().value());
758
759 fm.setMatch(match);
760
Jonathan Hart1912afc2013-10-11 12:02:44 +1300761 flowMods.add(new PushedFlowMod(flowEntry.dpid().value(), fm));
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700762
Jonathan Hart1912afc2013-10-11 12:02:44 +1300763 flowCache.write(flowEntry.dpid().value(), fm);
764
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700765 try {
766 fm = fm.clone();
767 } catch (CloneNotSupportedException e1) {
768 log.error("Failure cloning flow mod", e1);
769 }
770 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200771
772 return flowMods;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700773 }
774
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200775 private void setupBgpPaths(){
Jonathan Hartc824ad02013-07-03 15:58:45 +1200776 for (BgpPeer bgpPeer : bgpPeers.values()){
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200777 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
778
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700779 DataPath path = topologyNetService.getDatabaseShortestPath(
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200780 peerInterface.getSwitchPort(), bgpdAttachmentPoint);
781
782 if (path == null){
783 log.debug("Unable to compute path for BGP traffic for {}",
784 bgpPeer.getIpAddress());
785 continue;
786 }
787
788 //Set up the flow mod
789 OFFlowMod fm =
790 (OFFlowMod) floodlightProvider.getOFMessageFactory()
791 .getMessage(OFType.FLOW_MOD);
792
793 OFActionOutput action = new OFActionOutput();
794 action.setMaxLength((short)0xffff);
795 List<OFAction> actions = new ArrayList<OFAction>();
796 actions.add(action);
797
798 fm.setIdleTimeout((short)0)
799 .setHardTimeout((short)0)
800 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
801 .setCookie(BGP_COOKIE)
802 .setCommand(OFFlowMod.OFPFC_ADD)
803 .setPriority(SDNIP_PRIORITY)
804 .setActions(actions)
805 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
806
807 //Forward = gateway -> bgpd, reverse = bgpd -> gateway
808 OFMatch forwardMatchSrc = new OFMatch();
809
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200810 String interfaceCidrAddress = peerInterface.getIpAddress().getHostAddress()
811 + "/32";
812 String peerCidrAddress = bgpPeer.getIpAddress().getHostAddress()
813 + "/32";
Jonathan Hart38c84932013-08-10 17:49:27 +1200814
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200815 //Common match fields
816 forwardMatchSrc.setDataLayerType(Ethernet.TYPE_IPv4);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200817 forwardMatchSrc.setNetworkProtocol(IPv4.PROTOCOL_TCP);
Jonathan Hart1912afc2013-10-11 12:02:44 +1300818 //forwardMatchSrc.setTransportDestination(BGP_PORT);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200819 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_IN_PORT
820 & ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
821
822
823 OFMatch reverseMatchSrc = forwardMatchSrc.clone();
824
825 forwardMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_SRC);
826 forwardMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
827
828 OFMatch forwardMatchDst = forwardMatchSrc.clone();
829
830 forwardMatchSrc.setTransportSource(BGP_PORT);
831 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
832 forwardMatchDst.setTransportDestination(BGP_PORT);
833 forwardMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
834
835 reverseMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
836 reverseMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_DST);
837
838 OFMatch reverseMatchDst = reverseMatchSrc.clone();
839
840 reverseMatchSrc.setTransportSource(BGP_PORT);
841 reverseMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
842 reverseMatchDst.setTransportDestination(BGP_PORT);
843 reverseMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
844
845 fm.setMatch(forwardMatchSrc);
846
Jonathan Hart38c84932013-08-10 17:49:27 +1200847 OFMatch forwardIcmpMatch = new OFMatch();
848 forwardIcmpMatch.setDataLayerType(Ethernet.TYPE_IPv4);
849 forwardIcmpMatch.setNetworkProtocol(IPv4.PROTOCOL_ICMP);
850 forwardIcmpMatch.setWildcards(forwardIcmpMatch.getWildcards() &
851 ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
852
853 OFMatch reverseIcmpMatch = forwardIcmpMatch.clone();
854 forwardIcmpMatch.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
855 reverseIcmpMatch.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
856
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200857 for (FlowEntry flowEntry : path.flowEntries()){
858 OFFlowMod forwardFlowModSrc, forwardFlowModDst;
859 OFFlowMod reverseFlowModSrc, reverseFlowModDst;
Jonathan Hart38c84932013-08-10 17:49:27 +1200860 OFFlowMod forwardIcmp, reverseIcmp;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200861 try {
862 forwardFlowModSrc = fm.clone();
863 forwardFlowModDst = fm.clone();
864 reverseFlowModSrc = fm.clone();
865 reverseFlowModDst = fm.clone();
Jonathan Hart38c84932013-08-10 17:49:27 +1200866 forwardIcmp = fm.clone();
867 reverseIcmp = fm.clone();
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200868 } catch (CloneNotSupportedException e) {
869 log.warn("Clone failed", e);
870 continue;
871 }
872
873 forwardMatchSrc.setInputPort(flowEntry.inPort().value());
874 forwardFlowModSrc.setMatch(forwardMatchSrc);
875 ((OFActionOutput)forwardFlowModSrc.getActions().get(0))
876 .setPort(flowEntry.outPort().value());
877
878 forwardMatchDst.setInputPort(flowEntry.inPort().value());
879 forwardFlowModDst.setMatch(forwardMatchDst);
880 ((OFActionOutput)forwardFlowModDst.getActions().get(0))
881 .setPort(flowEntry.outPort().value());
882
883 reverseMatchSrc.setInputPort(flowEntry.outPort().value());
884 reverseFlowModSrc.setMatch(reverseMatchSrc);
885 ((OFActionOutput)reverseFlowModSrc.getActions().get(0))
886 .setPort(flowEntry.inPort().value());
887
888 reverseMatchDst.setInputPort(flowEntry.outPort().value());
889 reverseFlowModDst.setMatch(reverseMatchDst);
890 ((OFActionOutput)reverseFlowModDst.getActions().get(0))
891 .setPort(flowEntry.inPort().value());
892
Jonathan Hart38c84932013-08-10 17:49:27 +1200893 ((OFActionOutput)forwardIcmp.getActions().get(0))
894 .setPort(flowEntry.outPort().value());
895 forwardIcmp.setMatch(forwardIcmpMatch);
896
897 ((OFActionOutput)reverseIcmp.getActions().get(0))
898 .setPort(flowEntry.inPort().value());
899 reverseIcmp.setMatch(reverseIcmpMatch);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200900
Jonathan Hart1912afc2013-10-11 12:02:44 +1300901 List<OFFlowMod> flowModList = new ArrayList<OFFlowMod>(6);
902 flowModList.add(forwardFlowModSrc);
903 flowModList.add(forwardFlowModDst);
904 flowModList.add(reverseFlowModSrc);
905 flowModList.add(reverseFlowModDst);
906 flowModList.add(forwardIcmp);
907 flowModList.add(reverseIcmp);
908 flowCache.write(flowEntry.dpid().value(), flowModList);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200909 }
910 }
911 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200912
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200913 @Override
Jonathan Hartabad6a52013-09-30 18:17:21 +1300914 public void arpResponse(InetAddress ipAddress, MACAddress macAddress) {
915 log.debug("Received ARP response: {} => {}",
916 ipAddress.getHostAddress(), macAddress);
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200917
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200918 /*
919 * We synchronize on this to prevent changes to the ptree while we're pushing
920 * flows to the switches. If the ptree changes, the ptree and switches
921 * could get out of sync.
922 */
923 synchronized (this) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200924 Path path = pathsWaitingOnArp.remove(ipAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200925
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200926 if (path != null) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200927 log.debug("Pushing path to {} at {} on {}", new Object[] {
Jonathan Hartabad6a52013-09-30 18:17:21 +1300928 path.getDstIpAddress().getHostAddress(), macAddress,
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200929 path.getDstInterface().getSwitchPort()});
930 //These paths should always be to BGP peers. Paths to non-peers are
931 //handled once the first prefix is ready to push
932 if (pushedPaths.containsKey(path.getDstInterface())) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200933 //A path already got pushed to this endpoint while we were waiting
934 //for ARP. We'll copy over the permanent attribute if it is set on this path.
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200935 if (path.isPermanent()) {
936 pushedPaths.get(path.getDstInterface()).setPermanent();
Jonathan Hart309889c2013-08-13 23:26:24 +1200937 }
938 }
939 else {
Jonathan Hartabad6a52013-09-30 18:17:21 +1300940 calculateAndPushPath(path, macAddress);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200941 pushedPaths.put(path.getDstIpAddress(), path);
Jonathan Hart309889c2013-08-13 23:26:24 +1200942 }
943 }
944
Jonathan Hart309889c2013-08-13 23:26:24 +1200945 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
946
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200947 for (RibUpdate update : prefixesToPush) {
948 //These will always be adds
949
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200950 RibEntry rib = ptree.lookup(update.getPrefix());
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200951 if (rib != null && rib.equals(update.getRibEntry())) {
952 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200953 rib.getNextHop().getHostAddress());
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200954 //We only push prefix flows if the prefix is still in the ptree
955 //and the next hop is the same as our update. The prefix could
956 //have been removed while we were waiting for the ARP, or the
957 //next hop could have changed.
Jonathan Hart309889c2013-08-13 23:26:24 +1200958 _processRibAdd(update);
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200959 } else {
960 log.debug("Received ARP response, but {},{} is no longer in ptree",
961 update.getPrefix(), update.getRibEntry());
962 }
963 }
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200964 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200965 }
966
Jonathan Hartc82051c2013-08-24 15:12:20 +1200967 private void setupArpFlows() {
968 OFMatch match = new OFMatch();
969 match.setDataLayerType(Ethernet.TYPE_ARP);
970 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
971
972 OFFlowMod fm = new OFFlowMod();
973 fm.setMatch(match);
974
975 OFActionOutput action = new OFActionOutput();
976 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
977 action.setMaxLength((short)0xffff);
978 List<OFAction> actions = new ArrayList<OFAction>(1);
979 actions.add(action);
980 fm.setActions(actions);
981
982 fm.setIdleTimeout((short)0)
983 .setHardTimeout((short)0)
984 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
985 .setCookie(0)
986 .setCommand(OFFlowMod.OFPFC_ADD)
987 .setPriority(ARP_PRIORITY)
988 .setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
989
990 for (String strdpid : switches){
Jonathan Hart1912afc2013-10-11 12:02:44 +1300991 flowCache.write(HexString.toLong(strdpid), fm);
Jonathan Hartc82051c2013-08-24 15:12:20 +1200992 }
993 }
994
Jonathan Hartf886fa12013-09-18 14:46:29 +1200995 private void setupDefaultDropFlows() {
996 OFFlowMod fm = new OFFlowMod();
997 fm.setMatch(new OFMatch());
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +1200998 fm.setActions(new ArrayList<OFAction>()); //No action means drop
Jonathan Hartf886fa12013-09-18 14:46:29 +1200999
1000 fm.setIdleTimeout((short)0)
1001 .setHardTimeout((short)0)
1002 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1003 .setCookie(0)
1004 .setCommand(OFFlowMod.OFPFC_ADD)
1005 .setPriority((short)0)
1006 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
1007
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001008 OFFlowMod fmLLDP;
1009 OFFlowMod fmBDDP;
1010 try {
1011 fmLLDP = fm.clone();
1012 fmBDDP = fm.clone();
1013 } catch (CloneNotSupportedException e1) {
1014 log.error("Error cloning flow mod", e1);
1015 return;
1016 }
1017
1018 OFMatch matchLLDP = new OFMatch();
1019 matchLLDP.setDataLayerType((short)0x8942);
1020 matchLLDP.setWildcards(matchLLDP.getWildcards() & ~ OFMatch.OFPFW_DL_TYPE);
1021 fmLLDP.setMatch(matchLLDP);
1022
1023 OFMatch matchBDDP = new OFMatch();
1024 matchBDDP.setDataLayerType((short)0x88cc);
1025 matchBDDP.setWildcards(matchBDDP.getWildcards() & ~ OFMatch.OFPFW_DL_TYPE);
1026 fmBDDP.setMatch(matchBDDP);
1027
1028 OFActionOutput action = new OFActionOutput();
1029 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1030 action.setMaxLength((short)0xffff);
1031 List<OFAction> actions = new ArrayList<OFAction>(1);
1032 actions.add(action);
1033
1034 fmLLDP.setActions(actions);
1035 fmBDDP.setActions(actions);
1036
1037 fmLLDP.setPriority(ARP_PRIORITY);
1038 fmLLDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1039 fmBDDP.setPriority(ARP_PRIORITY);
1040 fmBDDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1041
Jonathan Hart1912afc2013-10-11 12:02:44 +13001042 List<OFFlowMod> flowModList = new ArrayList<OFFlowMod>(3);
1043 flowModList.add(fm);
1044 flowModList.add(fmLLDP);
1045 flowModList.add(fmBDDP);
1046
Jonathan Hartf886fa12013-09-18 14:46:29 +12001047 for (String strdpid : switches){
Jonathan Hart1912afc2013-10-11 12:02:44 +13001048 flowCache.write(HexString.toLong(strdpid), flowModList);
Jonathan Hartf886fa12013-09-18 14:46:29 +12001049 }
1050 }
1051
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001052 private void beginRouting(){
1053 log.debug("Topology is now ready, beginning routing function");
Pavlin Radoslavov15954d42013-10-19 15:29:04 -07001054 topology = topologyNetService.newDatabaseTopology();
Jonathan Hartdefa44d2013-08-15 19:51:13 +12001055
Jonathan Hartc82051c2013-08-24 15:12:20 +12001056 setupArpFlows();
Jonathan Hartf886fa12013-09-18 14:46:29 +12001057 setupDefaultDropFlows();
Jonathan Hartc82051c2013-08-24 15:12:20 +12001058
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001059 setupBgpPaths();
Jonathan Hart98957bf2013-07-01 14:49:24 +12001060 setupFullMesh();
Jonathan Harte7694532013-09-12 12:34:46 +12001061
1062 //Suppress link discovery on external-facing router ports
1063 for (Interface intf : interfaces.values()) {
1064 linkDiscoveryService.AddToSuppressLLDPs(intf.getDpid(), intf.getPort());
1065 }
1066
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001067 bgpUpdatesExecutor.execute(new Runnable() {
1068 @Override
1069 public void run() {
1070 doUpdatesThread();
1071 }
1072 });
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001073 }
1074
1075 private void checkSwitchesConnected(){
1076 for (String dpid : switches){
1077 if (floodlightProvider.getSwitches().get(HexString.toLong(dpid)) == null){
1078 log.debug("Not all switches are here yet");
1079 return;
1080 }
1081 }
1082 switchesConnected = true;
1083 }
1084
Jonathan Hartc824ad02013-07-03 15:58:45 +12001085 //Actually we only need to go half way round to verify full mesh connectivity
1086 //(n^2)/2
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001087 private void checkTopologyReady(){
Jonathan Hartc824ad02013-07-03 15:58:45 +12001088 for (Interface dstInterface : interfaces.values()) {
1089 for (Interface srcInterface : interfaces.values()) {
Jonathan Hart45107222013-10-22 17:35:04 -07001090 if (dstInterface.equals(srcInterface)) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001091 continue;
1092 }
1093
Pavlin Radoslavov15954d42013-10-19 15:29:04 -07001094 DataPath shortestPath = topologyNetService.getDatabaseShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +12001095 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001096
1097 if (shortestPath == null){
1098 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +12001099 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001100 return;
1101 }
1102 }
1103 }
1104 topologyReady = true;
1105 }
1106
1107 private void checkStatus(){
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001108 if (!switchesConnected){
1109 checkSwitchesConnected();
1110 }
1111 boolean oldTopologyReadyStatus = topologyReady;
1112 if (switchesConnected && !topologyReady){
1113 checkTopologyReady();
1114 }
1115 if (!oldTopologyReadyStatus && topologyReady){
1116 beginRouting();
1117 }
1118 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001119
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001120 private void doUpdatesThread() {
1121 boolean interrupted = false;
1122 try {
1123 while (true) {
1124 try {
1125 RibUpdate update = ribUpdates.take();
1126 switch (update.getOperation()){
1127 case UPDATE:
Jonathan Harte4c98692013-10-18 17:40:03 -07001128 if (validateUpdate(update)) {
1129 processRibAdd(update);
1130 }
1131 else {
1132 log.debug("Rib UPDATE out of order: {} via {}",
1133 update.getPrefix(), update.getRibEntry().getNextHop());
1134 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001135 break;
1136 case DELETE:
Jonathan Harte4c98692013-10-18 17:40:03 -07001137 if (validateUpdate(update)) {
1138 processRibDelete(update);
1139 }
1140 else {
1141 log.debug("Rib DELETE out of order: {} via {}",
1142 update.getPrefix(), update.getRibEntry().getNextHop());
1143 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001144 break;
1145 }
1146 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001147 log.debug("Interrupted while taking from updates queue", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001148 interrupted = true;
Jonathan Hart309889c2013-08-13 23:26:24 +12001149 } catch (Exception e) {
1150 log.debug("exception", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001151 }
1152 }
1153 } finally {
1154 if (interrupted) {
1155 Thread.currentThread().interrupt();
1156 }
1157 }
1158 }
Jonathan Harte4c98692013-10-18 17:40:03 -07001159
1160 private boolean validateUpdate(RibUpdate update) {
1161 RibEntry newEntry = update.getRibEntry();
1162 RibEntry oldEntry = ptree.lookup(update.getPrefix());
1163
1164 //If there is no existing entry we must assume this is the most recent
1165 //update. However this might not always be the case as we might have a
1166 //POST then DELETE reordering.
1167 //if (oldEntry == null || !newEntry.getNextHop().equals(oldEntry.getNextHop())) {
1168 if (oldEntry == null) {
1169 return true;
1170 }
1171
1172 // This handles the case where routes are gathered in the initial
1173 // request because they don't have sequence number info
1174 if (newEntry.getSysUpTime() == -1 && newEntry.getSequenceNum() == -1) {
1175 return true;
1176 }
1177
1178 if (newEntry.getSysUpTime() > oldEntry.getSysUpTime()) {
1179 return true;
1180 }
1181 else if (newEntry.getSysUpTime() == oldEntry.getSysUpTime()) {
1182 if (newEntry.getSequenceNum() > oldEntry.getSequenceNum()) {
1183 return true;
1184 }
1185 else {
1186 return false;
1187 }
1188 }
1189 else {
1190 return false;
1191 }
1192 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001193
1194 @Override
Jonathan Hart64c0b202013-08-20 15:45:07 +12001195 public void topologyChanged() {
1196 if (topologyReady) {
1197 return;
1198 }
1199
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001200 boolean refreshNeeded = false;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -07001201 for (LDUpdate ldu : topologyService.getLastLinkUpdates()){
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001202 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1203 //We don't need to recalculate anything for just link updates
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001204 //They happen very frequently
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001205 refreshNeeded = true;
1206 }
Jonathan Hart98957bf2013-07-01 14:49:24 +12001207
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001208 log.debug("Topo change {}", ldu.getOperation());
Jonathan Hartc824ad02013-07-03 15:58:45 +12001209
Jonathan Hart98957bf2013-07-01 14:49:24 +12001210 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1211 synchronized (linkUpdates) {
1212 linkUpdates.add(ldu);
1213 }
1214 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001215 }
1216
Jonathan Hart64c0b202013-08-20 15:45:07 +12001217 if (refreshNeeded && !topologyReady){
Jonathan Hart98957bf2013-07-01 14:49:24 +12001218 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
pingping-lina2cbfad2013-03-07 08:39:21 +08001219 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001220 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001221
1222 @Override
1223 public void addedSwitch(IOFSwitch sw) {
1224 if (!topologyReady) {
1225 sw.clearAllFlowMods();
1226 }
Jonathan Hart1912afc2013-10-11 12:02:44 +13001227
1228 flowCache.switchConnected(sw);
Jonathan Hart64c0b202013-08-20 15:45:07 +12001229 }
1230
1231 @Override
Jonathan Hart08ee8522013-09-22 17:34:43 +12001232 public void removedSwitch(IOFSwitch sw) {}
Jonathan Hart64c0b202013-08-20 15:45:07 +12001233
1234 @Override
Jonathan Hart08ee8522013-09-22 17:34:43 +12001235 public void switchPortChanged(Long switchId) {}
Jonathan Hart64c0b202013-08-20 15:45:07 +12001236
1237 @Override
1238 public String getName() {
Jonathan Hart08ee8522013-09-22 17:34:43 +12001239 return "BgpRoute";
1240 }
1241
1242 /*
Jonathan Harta8887642013-10-28 13:46:54 -07001243 * IConfigInfoService methods
Jonathan Hart08ee8522013-09-22 17:34:43 +12001244 */
1245
1246 @Override
1247 public boolean isInterfaceAddress(InetAddress address) {
1248 Interface intf = interfacePtrie.match(new Prefix(address.getAddress(), 32));
1249 return (intf != null && intf.getIpAddress().equals(address));
1250 }
1251
1252 @Override
1253 public boolean inConnectedNetwork(InetAddress address) {
1254 Interface intf = interfacePtrie.match(new Prefix(address.getAddress(), 32));
1255 return (intf != null && !intf.getIpAddress().equals(address));
1256 }
1257
1258 @Override
1259 public boolean fromExternalNetwork(long inDpid, short inPort) {
1260 for (Interface intf : interfaces.values()) {
1261 if (intf.getDpid() == inDpid && intf.getPort() == inPort) {
1262 return true;
1263 }
1264 }
1265 return false;
1266 }
1267
1268 @Override
1269 public Interface getOutgoingInterface(InetAddress dstIpAddress) {
1270 return interfacePtrie.match(new Prefix(dstIpAddress.getAddress(), 32));
1271 }
1272
1273 @Override
1274 public boolean hasLayer3Configuration() {
1275 return !interfaces.isEmpty();
1276 }
1277
1278 @Override
1279 public MACAddress getRouterMacAddress() {
1280 return bgpdMacAddress;
Jonathan Hart64c0b202013-08-20 15:45:07 +12001281 }
Jonathan Harta8887642013-10-28 13:46:54 -07001282
1283 @Override
1284 public short getVlan() {
1285 return vlan;
1286 }
Jonathan Hart5afde492013-10-01 12:30:53 +13001287
1288 /*
1289 * TODO This is a hack to get the REST API to work for ProxyArpManager.
1290 * The REST API is currently tied to the Floodlight module system and we
1291 * need to separate it to allow ONOS modules to use it. For now we will
1292 * proxy calls through to the ProxyArpManager (which is not a Floodlight
1293 * module) through this class which is a module.
1294 */
1295 @Override
1296 public MACAddress getMacAddress(InetAddress ipAddress) {
1297 return proxyArp.getMacAddress(ipAddress);
1298 }
1299
1300 @Override
1301 public void sendArpRequest(InetAddress ipAddress, IArpRequester requester,
1302 boolean retry) {
1303 proxyArp.sendArpRequest(ipAddress, requester, retry);
1304 }
1305
1306 @Override
1307 public List<String> getMappings() {
1308 return proxyArp.getMappings();
1309 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001310}