blob: 97b3a68b7171f29a8dd5c3f81563b901c52c5370 [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;
Jonathan Hartc7ca35d2013-06-25 20:54:25 +120043import net.onrc.onos.ofcontroller.proxyarp.ProxyArpManager;
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -070044import net.onrc.onos.ofcontroller.topology.ITopologyNetService;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070045import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavove1b37bc2013-10-16 03:57:06 -070046import net.onrc.onos.ofcontroller.topology.TopologyManager;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070047import net.onrc.onos.ofcontroller.util.DataPath;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120048import net.onrc.onos.ofcontroller.util.Dpid;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070049import net.onrc.onos.ofcontroller.util.FlowEntry;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070050import net.onrc.onos.ofcontroller.util.Port;
51import net.onrc.onos.ofcontroller.util.SwitchPort;
pingping-line2a09ca2013-03-23 09:33:58 +080052import net.sf.json.JSONArray;
53import net.sf.json.JSONObject;
54import net.sf.json.JSONSerializer;
pingping-lina2cbfad2013-03-07 08:39:21 +080055
Jonathan Hartd1f23252013-06-13 15:17:05 +120056import org.codehaus.jackson.JsonParseException;
57import org.codehaus.jackson.map.JsonMappingException;
58import org.codehaus.jackson.map.ObjectMapper;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070059import org.openflow.protocol.OFFlowMod;
60import org.openflow.protocol.OFMatch;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070061import org.openflow.protocol.OFPacketOut;
Jonathan Hart9575cb62013-07-05 13:43:49 +120062import org.openflow.protocol.OFPort;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070063import org.openflow.protocol.OFType;
64import org.openflow.protocol.action.OFAction;
65import org.openflow.protocol.action.OFActionDataLayerDestination;
66import org.openflow.protocol.action.OFActionOutput;
Jonathan Hart1236a9b2013-06-18 22:10:05 +120067import org.openflow.util.HexString;
pingping-lina2cbfad2013-03-07 08:39:21 +080068import org.slf4j.Logger;
69import org.slf4j.LoggerFactory;
70
Jonathan Hart4dfc3652013-08-02 20:22:36 +120071import com.google.common.collect.HashMultimap;
Jonathan Hart0ee0f022013-08-03 22:21:54 +120072import com.google.common.collect.Multimap;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120073import com.google.common.collect.Multimaps;
74import com.google.common.collect.SetMultimap;
Jonathan Hart309889c2013-08-13 23:26:24 +120075import com.google.common.net.InetAddresses;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120076import com.google.common.util.concurrent.ThreadFactoryBuilder;
77
Jonathan Hart1236a9b2013-06-18 22:10:05 +120078public class BgpRoute implements IFloodlightModule, IBgpRouteService,
Jonathan Hart64c0b202013-08-20 15:45:07 +120079 ITopologyListener, IArpRequester,
Jonathan Hart5afde492013-10-01 12:30:53 +130080 IOFSwitchListener, ILayer3InfoService,
81 IProxyArpService {
pingping-lina2cbfad2013-03-07 08:39:21 +080082
Jonathan Hartf247ee72013-10-18 18:57:28 -070083 private static Logger log = LoggerFactory.getLogger(BgpRoute.class);
pingping-lina2cbfad2013-03-07 08:39:21 +080084
Jonathan Hartf247ee72013-10-18 18:57:28 -070085 private IFloodlightProviderService floodlightProvider;
Jonathan Hart3a326122013-10-21 11:51:13 -070086 private ITopologyService topologyService;
Jonathan Hartf247ee72013-10-18 18:57:28 -070087 private ITopologyNetService topologyNetService;
88 private ILinkDiscoveryService linkDiscoveryService;
89 private IRestApiService restApi;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070090
Jonathan Hartf247ee72013-10-18 18:57:28 -070091 private ProxyArpManager proxyArp;
Jonathan Hartc7ca35d2013-06-25 20:54:25 +120092
Jonathan Hartf247ee72013-10-18 18:57:28 -070093 private IPatriciaTrie<RibEntry> ptree;
94 private IPatriciaTrie<Interface> interfacePtrie;
95 private BlockingQueue<RibUpdate> ribUpdates;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120096
Jonathan Hartf247ee72013-10-18 18:57:28 -070097 private String bgpdRestIp;
98 private String routerId;
99 private String configFilename = "config.json";
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700100
101 //We need to identify our flows somehow. But like it says in LearningSwitch.java,
102 //the controller/OS should hand out cookie IDs to prevent conflicts.
Jonathan Hartf247ee72013-10-18 18:57:28 -0700103 private final long APP_COOKIE = 0xa0000000000000L;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700104 //Cookie for flows that do L2 forwarding within SDN domain to egress routers
Jonathan Hartf247ee72013-10-18 18:57:28 -0700105 private final long L2_FWD_COOKIE = APP_COOKIE + 1;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700106 //Cookie for flows in ingress switches that rewrite the MAC address
Jonathan Hartf247ee72013-10-18 18:57:28 -0700107 private final long MAC_RW_COOKIE = APP_COOKIE + 2;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200108 //Cookie for flows that setup BGP paths
Jonathan Hartf247ee72013-10-18 18:57:28 -0700109 private final long BGP_COOKIE = APP_COOKIE + 3;
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200110 //Forwarding uses priority 0, and the mac rewrite entries in ingress switches
111 //need to be higher priority than this otherwise the rewrite may not get done
Jonathan Hartf247ee72013-10-18 18:57:28 -0700112 private final short SDNIP_PRIORITY = 10;
113 private final short ARP_PRIORITY = 20;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700114
Jonathan Hartf247ee72013-10-18 18:57:28 -0700115 private final short BGP_PORT = 179;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200116
Jonathan Hartf247ee72013-10-18 18:57:28 -0700117 private final int TOPO_DETECTION_WAIT = 2; //seconds
Jonathan Hart98957bf2013-07-01 14:49:24 +1200118
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200119 //Configuration stuff
Jonathan Hartf247ee72013-10-18 18:57:28 -0700120 private List<String> switches;
121 private Map<String, Interface> interfaces;
122 private Map<InetAddress, BgpPeer> bgpPeers;
123 private SwitchPort bgpdAttachmentPoint;
124 private MACAddress bgpdMacAddress;
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700125 private short vlan;
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200126
127 //True when all switches have connected
Jonathan Hartf247ee72013-10-18 18:57:28 -0700128 private volatile boolean switchesConnected = false;
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200129 //True when we have a full mesh of shortest paths between gateways
Jonathan Hartf247ee72013-10-18 18:57:28 -0700130 private volatile boolean topologyReady = false;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200131
Jonathan Hartf247ee72013-10-18 18:57:28 -0700132 private ArrayList<LDUpdate> linkUpdates;
133 private SingletonTask topologyChangeDetectorTask;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200134
Jonathan Hartf247ee72013-10-18 18:57:28 -0700135 private SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
Jonathan Hart309889c2013-08-13 23:26:24 +1200136
Jonathan Hartf247ee72013-10-18 18:57:28 -0700137 private Map<InetAddress, Path> pathsWaitingOnArp;
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200138
Jonathan Hartf247ee72013-10-18 18:57:28 -0700139 private ExecutorService bgpUpdatesExecutor;
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200140
Jonathan Hartf247ee72013-10-18 18:57:28 -0700141 private Map<InetAddress, Path> pushedPaths;
142 private Map<Prefix, Path> prefixToPath;
143 private Multimap<Prefix, PushedFlowMod> pushedFlows;
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200144
Jonathan Hart1912afc2013-10-11 12:02:44 +1300145 private FlowCache flowCache;
146
Jonathan Hart3a326122013-10-21 11:51:13 -0700147 private volatile Topology topology = null;
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200148
Jonathan Hartf247ee72013-10-18 18:57:28 -0700149 private class TopologyChangeDetector implements Runnable {
Jonathan Hart98957bf2013-07-01 14:49:24 +1200150 @Override
151 public void run() {
152 log.debug("Running topology change detection task");
153 synchronized (linkUpdates) {
Jonathan Hartc824ad02013-07-03 15:58:45 +1200154 //This is the model the REST API uses to retrieve network graph info
Jonathan Hart98957bf2013-07-01 14:49:24 +1200155 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
156
157 List<Link> activeLinks = topoLinkService.getActiveLinks();
Jonathan Hart98957bf2013-07-01 14:49:24 +1200158
159 Iterator<LDUpdate> it = linkUpdates.iterator();
160 while (it.hasNext()){
161 LDUpdate ldu = it.next();
162 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
163 ldu.getDst(), ldu.getDstPort());
164
165 if (activeLinks.contains(l)){
Jonathan Hart98957bf2013-07-01 14:49:24 +1200166 it.remove();
167 }
168 }
169 }
170
Jonathan Hart64c0b202013-08-20 15:45:07 +1200171 if (!topologyReady) {
172 if (linkUpdates.isEmpty()){
173 //All updates have been seen in network map.
174 //We can check if topology is ready
175 log.debug("No known changes outstanding. Checking topology now");
176 checkStatus();
177 }
178 else {
179 //We know of some link updates that haven't propagated to the database yet
180 log.debug("Some changes not found in network map - {} links missing", linkUpdates.size());
181 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
182 }
Jonathan Hart98957bf2013-07-01 14:49:24 +1200183 }
184 }
185 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700186
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700187 private void readConfiguration(String configFilename){
188 File gatewaysFile = new File(configFilename);
Jonathan Hartd1f23252013-06-13 15:17:05 +1200189 ObjectMapper mapper = new ObjectMapper();
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700190
Jonathan Hartd1f23252013-06-13 15:17:05 +1200191 try {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200192 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
193
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200194 switches = config.getSwitches();
Jonathan Hart9575cb62013-07-05 13:43:49 +1200195 interfaces = new HashMap<String, Interface>();
196 for (Interface intf : config.getInterfaces()){
197 interfaces.put(intf.getName(), intf);
198 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200199 bgpPeers = new HashMap<InetAddress, BgpPeer>();
200 for (BgpPeer peer : config.getPeers()){
201 bgpPeers.put(peer.getIpAddress(), peer);
202 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200203
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200204 bgpdAttachmentPoint = new SwitchPort(
205 new Dpid(config.getBgpdAttachmentDpid()),
206 new Port(config.getBgpdAttachmentPort()));
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200207
Jonathan Hart2f790d22013-08-15 14:01:24 +1200208 bgpdMacAddress = config.getBgpdMacAddress();
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700209 vlan = config.getVlan();
Jonathan Hartd1f23252013-06-13 15:17:05 +1200210 } catch (JsonParseException e) {
211 log.error("Error in JSON file", e);
212 System.exit(1);
213 } catch (JsonMappingException e) {
214 log.error("Error in JSON file", e);
215 System.exit(1);
216 } catch (IOException e) {
217 log.error("Error reading JSON file", e);
218 System.exit(1);
219 }
Jonathan Hartabf10222013-08-13 10:19:34 +1200220
221 //Populate the interface Patricia Trie
222 for (Interface intf : interfaces.values()) {
223 Prefix prefix = new Prefix(intf.getIpAddress().getAddress(), intf.getPrefixLength());
224 interfacePtrie.put(prefix, intf);
225 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700226 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800227
228 @Override
229 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700230 Collection<Class<? extends IFloodlightService>> l
231 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800232 l.add(IBgpRouteService.class);
233 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 Hart5afde492013-10-01 12:30:53 +1300241 m.put(IProxyArpService.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
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700272 proxyArp = new ProxyArpManager(floodlightProvider, topologyService, this, restApi);
pingping-lina2cbfad2013-03-07 08:39:21 +0800273
Jonathan Hart98957bf2013-07-01 14:49:24 +1200274 linkUpdates = new ArrayList<LDUpdate>();
275 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
276 topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700277
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -0700278 topologyNetService = new TopologyManager("");
Jonathan Hart98957bf2013-07-01 14:49:24 +1200279
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200280 pathsWaitingOnArp = new HashMap<InetAddress, Path>();
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200281 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
282 HashMultimap.<InetAddress, RibUpdate>create());
283
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200284 pushedPaths = new HashMap<InetAddress, Path>();
285 prefixToPath = new HashMap<Prefix, Path>();
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200286 pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
287
Jonathan Hart1912afc2013-10-11 12:02:44 +1300288 flowCache = new FlowCache(floodlightProvider);
289
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200290 bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
291 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
292
Jonathan Hart61ba9372013-05-19 20:10:29 -0700293 //Read in config values
294 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
295 if (bgpdRestIp == null){
296 log.error("BgpdRestIp property not found in config file");
297 System.exit(1);
298 }
299 else {
300 log.info("BgpdRestIp set to {}", bgpdRestIp);
301 }
302
303 routerId = context.getConfigParams(this).get("RouterId");
304 if (routerId == null){
305 log.error("RouterId property not found in config file");
306 System.exit(1);
307 }
308 else {
309 log.info("RouterId set to {}", routerId);
310 }
Jonathan Hartd1f23252013-06-13 15:17:05 +1200311
Jonathan Hart9575cb62013-07-05 13:43:49 +1200312 String configFilenameParameter = context.getConfigParams(this).get("configfile");
313 if (configFilenameParameter != null){
314 configFilename = configFilenameParameter;
315 }
316 log.debug("Config file set to {}", configFilename);
317
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700318 readConfiguration(configFilename);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200319 }
320
321 @Override
322 public void startUp(FloodlightModuleContext context) {
323 restApi.addRestletRoutable(new BgpRouteWebRoutable());
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700324 topologyService.addListener(this);
Jonathan Hart64c0b202013-08-20 15:45:07 +1200325 floodlightProvider.addOFSwitchListener(this);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200326
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700327 proxyArp.startUp(vlan);
Jonathan Hart2f790d22013-08-15 14:01:24 +1200328
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200329 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, proxyArp);
330
331 //Retrieve the RIB from BGPd during startup
332 retrieveRib();
pingping-lina2cbfad2013-03-07 08:39:21 +0800333 }
334
Jonathan Hart29b972d2013-08-12 23:43:51 +1200335 public IPatriciaTrie<RibEntry> getPtree() {
pingping-lina2cbfad2013-03-07 08:39:21 +0800336 return ptree;
337 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700338
339 public void clearPtree() {
Jonathan Hart29b972d2013-08-12 23:43:51 +1200340 ptree = new PatriciaTrie<RibEntry>(32);
pingping-line2a09ca2013-03-23 09:33:58 +0800341 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700342
pingping-line2a09ca2013-03-23 09:33:58 +0800343 public String getBGPdRestIp() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700344 return bgpdRestIp;
pingping-line2a09ca2013-03-23 09:33:58 +0800345 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700346
pingping-line2a09ca2013-03-23 09:33:58 +0800347 public String getRouterId() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700348 return routerId;
pingping-line2a09ca2013-03-23 09:33:58 +0800349 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800350
Jonathan Hart61ba9372013-05-19 20:10:29 -0700351 private void retrieveRib(){
352 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
353 String response = RestClient.get(url);
354
355 if (response.equals("")){
356 return;
357 }
358
359 response = response.replaceAll("\"", "'");
360 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
361 JSONArray rib_json_array = jsonObj.getJSONArray("rib");
362 String router_id = jsonObj.getString("router-id");
363
364 int size = rib_json_array.size();
365
366 log.info("Retrived RIB of {} entries from BGPd", size);
367
368 for (int j = 0; j < size; j++) {
369 JSONObject second_json_object = rib_json_array.getJSONObject(j);
370 String prefix = second_json_object.getString("prefix");
371 String nexthop = second_json_object.getString("nexthop");
372
373 //insert each rib entry into the local rib;
374 String[] substring = prefix.split("/");
375 String prefix1 = substring[0];
376 String mask1 = substring[1];
377
378 Prefix p;
379 try {
380 p = new Prefix(prefix1, Integer.valueOf(mask1));
381 } catch (NumberFormatException e) {
382 log.warn("Wrong mask format in RIB JSON: {}", mask1);
383 continue;
Jonathan Hart32e18222013-08-07 22:05:42 +1200384 } catch (IllegalArgumentException e1) {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700385 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
386 continue;
387 }
388
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200389 RibEntry rib = new RibEntry(router_id, nexthop);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200390
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200391 try {
392 ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
393 } catch (InterruptedException e) {
394 log.debug("Interrupted while pushing onto update queue");
395 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700396 }
397 }
398
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200399 @Override
400 public void newRibUpdate(RibUpdate update) {
Jonathan Hart9ea31212013-08-12 21:40:34 +1200401 try {
402 ribUpdates.put(update);
403 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200404 log.debug("Interrupted while putting on ribUpdates queue", e);
405 Thread.currentThread().interrupt();
Jonathan Hart9ea31212013-08-12 21:40:34 +1200406 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200407 }
408
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200409 public synchronized void processRibAdd(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200410 Prefix prefix = update.getPrefix();
411
Jonathan Hart9ea31212013-08-12 21:40:34 +1200412 log.debug("Processing prefix add {}", prefix);
413
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200414 RibEntry rib = ptree.put(prefix, update.getRibEntry());
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200415
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200416 if (rib != null && !rib.equals(update.getRibEntry())) {
Jonathan Hart2f740782013-08-04 00:49:21 +1200417 //There was an existing nexthop for this prefix. This update supersedes that,
418 //so we need to remove the old flows for this prefix from the switches
Jonathan Hart309889c2013-08-13 23:26:24 +1200419 _processDeletePrefix(prefix, rib);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200420 }
Jonathan Hart2f740782013-08-04 00:49:21 +1200421
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200422 if (update.getRibEntry().getNextHop().equals(
423 InetAddresses.forString("0.0.0.0"))) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200424 //Route originated by SDN domain
425 //We don't handle these at the moment
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200426 log.debug("Own route {} to {}", prefix,
427 update.getRibEntry().getNextHop().getHostAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200428 return;
429 }
430
431 _processRibAdd(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200432 }
433
Jonathan Hart309889c2013-08-13 23:26:24 +1200434 private void _processRibAdd(RibUpdate update) {
435 Prefix prefix = update.getPrefix();
436 RibEntry rib = update.getRibEntry();
437
438 InetAddress dstIpAddress = rib.getNextHop();
439
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200440 //See if we know the MAC address of the next hop
Jonathan Hartabad6a52013-09-30 18:17:21 +1300441 MACAddress nextHopMacAddress = proxyArp.getMacAddress(rib.getNextHop());
Jonathan Hart309889c2013-08-13 23:26:24 +1200442
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200443 //Find the attachment point (egress interface) of the next hop
444 Interface egressInterface = null;
Jonathan Hart309889c2013-08-13 23:26:24 +1200445 if (bgpPeers.containsKey(dstIpAddress)) {
446 //Route to a peer
447 log.debug("Route to peer {}", dstIpAddress);
448 BgpPeer peer = bgpPeers.get(dstIpAddress);
449 egressInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart309889c2013-08-13 23:26:24 +1200450 }
451 else {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200452 //Route to non-peer
Jonathan Hart309889c2013-08-13 23:26:24 +1200453 log.debug("Route to non-peer {}", dstIpAddress);
454 egressInterface = interfacePtrie.match(
455 new Prefix(dstIpAddress.getAddress(), 32));
456 if (egressInterface == null) {
457 log.warn("No outgoing interface found for {}", dstIpAddress.getHostAddress());
458 return;
459 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200460 }
461
462 if (nextHopMacAddress == null) {
463 prefixesWaitingOnArp.put(dstIpAddress,
464 new RibUpdate(Operation.UPDATE, prefix, rib));
465 proxyArp.sendArpRequest(dstIpAddress, this, true);
466 return;
467 }
468 else {
469 if (!bgpPeers.containsKey(dstIpAddress)) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200470 //If the prefix is for a non-peer we need to ensure there's a path,
471 //and push one if there isn't.
472 Path path = pushedPaths.get(dstIpAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200473 if (path == null) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200474 path = new Path(egressInterface, dstIpAddress);
Jonathan Hartabad6a52013-09-30 18:17:21 +1300475 calculateAndPushPath(path, nextHopMacAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200476 pushedPaths.put(dstIpAddress, path);
477 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200478
479 path.incrementUsers();
480 prefixToPath.put(prefix, path);
481 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200482
483 //For all prefixes we need to add the first-hop mac-rewriting flows
Jonathan Hart309889c2013-08-13 23:26:24 +1200484 addPrefixFlows(prefix, egressInterface, nextHopMacAddress);
485 }
486 }
487
Jonathan Hartabad6a52013-09-30 18:17:21 +1300488 private void addPrefixFlows(Prefix prefix, Interface egressInterface, MACAddress nextHopMacAddress) {
Jonathan Harte4c98692013-10-18 17:40:03 -0700489 log.debug("Adding flows for prefix {}, next hop mac {}",
Jonathan Hartabad6a52013-09-30 18:17:21 +1300490 prefix, nextHopMacAddress);
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200491
492 //We only need one flow mod per switch, so pick one interface on each switch
493 Map<Long, Interface> srcInterfaces = new HashMap<Long, Interface>();
494 for (Interface intf : interfaces.values()) {
495 if (!srcInterfaces.containsKey(intf.getDpid())
Jonathan Hart45107222013-10-22 17:35:04 -0700496 && !intf.equals(egressInterface)) {
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200497 srcInterfaces.put(intf.getDpid(), intf);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200498 }
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200499 }
500
501 //Add a flow to rewrite mac for this prefix to all other border switches
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200502 for (Interface srcInterface : srcInterfaces.values()) {
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200503 DataPath shortestPath;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700504 if (topology == null) {
505 shortestPath = topologyNetService.getDatabaseShortestPath(
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200506 srcInterface.getSwitchPort(),
507 egressInterface.getSwitchPort());
508 }
509 else {
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700510 shortestPath = topologyNetService.getTopologyShortestPath(
511 topology, srcInterface.getSwitchPort(),
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200512 egressInterface.getSwitchPort());
513 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200514
515 if (shortestPath == null){
516 log.debug("Shortest path between {} and {} not found",
517 srcInterface.getSwitchPort(),
518 egressInterface.getSwitchPort());
519 return; // just quit here?
520 }
521
522 //Set up the flow mod
523 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
524 .getMessage(OFType.FLOW_MOD);
525
526 fm.setIdleTimeout((short)0)
527 .setHardTimeout((short)0)
528 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
529 .setCookie(MAC_RW_COOKIE)
530 .setCommand(OFFlowMod.OFPFC_ADD)
531 .setPriority(SDNIP_PRIORITY)
532 .setLengthU(OFFlowMod.MINIMUM_LENGTH
533 + OFActionDataLayerDestination.MINIMUM_LENGTH
534 + OFActionOutput.MINIMUM_LENGTH);
535
536 OFMatch match = new OFMatch();
537 match.setDataLayerType(Ethernet.TYPE_IPv4);
538 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
539
540 match.setFromCIDR(prefix.toString(), OFMatch.STR_NW_DST);
541 fm.setMatch(match);
542
543 //Set up MAC rewrite action
544 OFActionDataLayerDestination macRewriteAction = new OFActionDataLayerDestination();
Jonathan Hartabad6a52013-09-30 18:17:21 +1300545 macRewriteAction.setDataLayerAddress(nextHopMacAddress.toBytes());
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200546
547 //Set up output action
548 OFActionOutput outputAction = new OFActionOutput();
549 outputAction.setMaxLength((short)0xffff);
550 Port outputPort = shortestPath.flowEntries().get(0).outPort();
551 outputAction.setPort(outputPort.value());
552
553 List<OFAction> actions = new ArrayList<OFAction>();
554 actions.add(macRewriteAction);
555 actions.add(outputAction);
556 fm.setActions(actions);
557
Jonathan Hart1912afc2013-10-11 12:02:44 +1300558 pushedFlows.put(prefix, new PushedFlowMod(srcInterface.getDpid(), fm));
559 flowCache.write(srcInterface.getDpid(), fm);
560
561 /*
562 * XXX Rate limit hack!
563 * This should be solved properly by adding a rate limiting
564 * layer on top of the switches if we know they need it.
565 */
566 try {
Jonathan Hart9971e1c2013-09-17 10:47:40 +1200567 Thread.sleep(1);
Jonathan Hart65139e42013-09-13 16:52:25 +1200568 } catch (InterruptedException e) {
569 // TODO handle this properly
570 log.error("Interrupted", e);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200571 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200572 }
573 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200574
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200575 public synchronized void processRibDelete(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200576 Prefix prefix = update.getPrefix();
577
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200578 if (ptree.remove(prefix, update.getRibEntry())) {
579 /*
580 * Only delete flows if an entry was actually removed from the trie.
581 * If no entry was removed, the <prefix, nexthop> wasn't there so
582 * it's probably already been removed and we don't need to do anything
583 */
Jonathan Hart309889c2013-08-13 23:26:24 +1200584 _processDeletePrefix(prefix, update.getRibEntry());
Jonathan Hart309889c2013-08-13 23:26:24 +1200585 }
586 }
587
588 private void _processDeletePrefix(Prefix prefix, RibEntry ribEntry) {
589 deletePrefixFlows(prefix);
590
591 log.debug("Deleting {} to {}", prefix, ribEntry.getNextHop());
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200592
Jonathan Hart309889c2013-08-13 23:26:24 +1200593 if (!bgpPeers.containsKey(ribEntry.getNextHop())) {
594 log.debug("Getting path for route with non-peer nexthop");
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200595 Path path = prefixToPath.remove(prefix);
Jonathan Hart309889c2013-08-13 23:26:24 +1200596
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200597 if (path != null) {
598 //path could be null if we added to the Ptree but didn't push
599 //flows yet because we were waiting to resolve ARP
Jonathan Hart309889c2013-08-13 23:26:24 +1200600
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200601 path.decrementUsers();
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200602 if (path.getUsers() <= 0 && !path.isPermanent()) {
603 deletePath(path);
604 pushedPaths.remove(path.getDstIpAddress());
605 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200606 }
607 }
608 }
609
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200610 private void deletePrefixFlows(Prefix prefix) {
611 log.debug("Deleting flows for prefix {}", prefix);
612
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200613 Collection<PushedFlowMod> pushedFlowMods
614 = pushedFlows.removeAll(prefix);
615
616 for (PushedFlowMod pfm : pushedFlowMods) {
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200617 if (log.isTraceEnabled()) {
618 log.trace("Pushing a DELETE flow mod to {}, matches prefix {} with mac-rewrite {}",
619 new Object[] {HexString.toHexString(pfm.getDpid()),
620 pfm.getFlowMod().getMatch().getNetworkDestination() +
621 pfm.getFlowMod().getMatch().getNetworkDestinationMaskLen(),
622 HexString.toHexString(((OFActionDataLayerDestination)pfm.getFlowMod().getActions().get(0))
623 .getDataLayerAddress())});
624 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200625
626 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
627 }
628 }
629
630 private void deletePath(Path path) {
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200631 log.debug("Deleting flows for path to {}",
632 path.getDstIpAddress().getHostAddress());
633
Jonathan Hart309889c2013-08-13 23:26:24 +1200634 for (PushedFlowMod pfm : path.getFlowMods()) {
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200635 if (log.isTraceEnabled()) {
636 log.trace("Pushing a DELETE flow mod to {}, dst MAC {}",
637 new Object[] {HexString.toHexString(pfm.getDpid()),
638 HexString.toHexString(pfm.getFlowMod().getMatch().getDataLayerDestination())
639 });
640 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200641
642 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
643 }
644 }
645
646 private void sendDeleteFlowMod(OFFlowMod addFlowMod, long dpid) {
Jonathan Hart1912afc2013-10-11 12:02:44 +1300647 flowCache.delete(dpid, addFlowMod);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200648 }
649
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200650 //TODO test next-hop changes
Jonathan Hart2f740782013-08-04 00:49:21 +1200651 //TODO check delete/add synchronization
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200652
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700653 /*
654 * On startup we need to calculate a full mesh of paths between all gateway
655 * switches
656 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200657 private void setupFullMesh(){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700658 //For each border router, calculate and install a path from every other
659 //border switch to said border router. However, don't install the entry
660 //in to the first hop switch, as we need to install an entry to rewrite
661 //for each prefix received. This will be done later when prefixes have
662 //actually been received.
663
Jonathan Hartc824ad02013-07-03 15:58:45 +1200664 for (BgpPeer peer : bgpPeers.values()) {
665 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200666
Jonathan Hart309889c2013-08-13 23:26:24 +1200667 //We know there's not already a Path here pushed, because this is
668 //called before all other routing
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200669 Path path = new Path(peerInterface, peer.getIpAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200670 path.setPermanent();
671
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200672 //See if we know the MAC address of the peer. If not we can't
673 //do anything until we learn it
Jonathan Hartabad6a52013-09-30 18:17:21 +1300674 MACAddress macAddress = proxyArp.getMacAddress(peer.getIpAddress());
675 if (macAddress == null) {
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200676 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
677 //Put in the pending paths list first
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200678 pathsWaitingOnArp.put(peer.getIpAddress(), path);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700679
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200680 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
681 continue;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700682 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200683
684 //If we know the MAC, lets go ahead and push the paths to this peer
Jonathan Hartabad6a52013-09-30 18:17:21 +1300685 calculateAndPushPath(path, macAddress);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700686 }
687 }
688
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200689 private void calculateAndPushPath(Path path, MACAddress dstMacAddress) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200690 Interface dstInterface = path.getDstInterface();
691
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200692 log.debug("Setting up path to {}, {}", path.getDstIpAddress().getHostAddress(),
693 dstMacAddress);
694
Jonathan Hart309889c2013-08-13 23:26:24 +1200695 List<PushedFlowMod> pushedFlows = new ArrayList<PushedFlowMod>();
696
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200697 for (Interface srcInterface : interfaces.values()) {
Jonathan Hart45107222013-10-22 17:35:04 -0700698 if (dstInterface.equals(srcInterface)){
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200699 continue;
700 }
701
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200702 DataPath shortestPath;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700703 if (topology == null) {
704 shortestPath = topologyNetService.getDatabaseShortestPath(
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200705 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
706 }
707 else {
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700708 shortestPath = topologyNetService.getTopologyShortestPath(topology,
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200709 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
710 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200711
712 if (shortestPath == null){
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200713 log.warn("Shortest path between {} and {} not found",
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200714 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200715 return;
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200716 }
717
Jonathan Hart1912afc2013-10-11 12:02:44 +1300718 List<PushedFlowMod> pushedFlowMods = installPath(shortestPath.flowEntries(), dstMacAddress);
719 pushedFlows.addAll(pushedFlowMods);
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200720 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200721
722 path.setFlowMods(pushedFlows);
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200723 }
724
Jonathan Hart309889c2013-08-13 23:26:24 +1200725 private List<PushedFlowMod> installPath(List<FlowEntry> flowEntries, MACAddress dstMacAddress){
726 List<PushedFlowMod> flowMods = new ArrayList<PushedFlowMod>();
727
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700728 //Set up the flow mod
729 OFFlowMod fm =
730 (OFFlowMod) floodlightProvider.getOFMessageFactory()
731 .getMessage(OFType.FLOW_MOD);
732
733 OFActionOutput action = new OFActionOutput();
734 action.setMaxLength((short)0xffff);
735 List<OFAction> actions = new ArrayList<OFAction>();
736 actions.add(action);
737
738 fm.setIdleTimeout((short)0)
739 .setHardTimeout((short)0)
740 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
741 .setCookie(L2_FWD_COOKIE)
742 .setCommand(OFFlowMod.OFPFC_ADD)
Jonathan Hartbdc87462013-09-24 15:03:23 +1200743 .setPriority(SDNIP_PRIORITY)
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700744 .setActions(actions)
745 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
746
747 //Don't push the first flow entry. We need to push entries in the
748 //first switch based on IP prefix which we don't know yet.
749 for (int i = 1; i < flowEntries.size(); i++){
750 FlowEntry flowEntry = flowEntries.get(i);
751
752 OFMatch match = new OFMatch();
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200753 match.setDataLayerDestination(dstMacAddress.toBytes());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700754 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
755 ((OFActionOutput) fm.getActions().get(0)).setPort(flowEntry.outPort().value());
756
757 fm.setMatch(match);
758
Jonathan Hart1912afc2013-10-11 12:02:44 +1300759 flowMods.add(new PushedFlowMod(flowEntry.dpid().value(), fm));
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700760
Jonathan Hart1912afc2013-10-11 12:02:44 +1300761 flowCache.write(flowEntry.dpid().value(), fm);
762
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700763 try {
764 fm = fm.clone();
765 } catch (CloneNotSupportedException e1) {
766 log.error("Failure cloning flow mod", e1);
767 }
768 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200769
770 return flowMods;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700771 }
772
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200773 private void setupBgpPaths(){
Jonathan Hartc824ad02013-07-03 15:58:45 +1200774 for (BgpPeer bgpPeer : bgpPeers.values()){
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200775 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
776
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700777 DataPath path = topologyNetService.getDatabaseShortestPath(
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200778 peerInterface.getSwitchPort(), bgpdAttachmentPoint);
779
780 if (path == null){
781 log.debug("Unable to compute path for BGP traffic for {}",
782 bgpPeer.getIpAddress());
783 continue;
784 }
785
786 //Set up the flow mod
787 OFFlowMod fm =
788 (OFFlowMod) floodlightProvider.getOFMessageFactory()
789 .getMessage(OFType.FLOW_MOD);
790
791 OFActionOutput action = new OFActionOutput();
792 action.setMaxLength((short)0xffff);
793 List<OFAction> actions = new ArrayList<OFAction>();
794 actions.add(action);
795
796 fm.setIdleTimeout((short)0)
797 .setHardTimeout((short)0)
798 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
799 .setCookie(BGP_COOKIE)
800 .setCommand(OFFlowMod.OFPFC_ADD)
801 .setPriority(SDNIP_PRIORITY)
802 .setActions(actions)
803 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
804
805 //Forward = gateway -> bgpd, reverse = bgpd -> gateway
806 OFMatch forwardMatchSrc = new OFMatch();
807
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200808 String interfaceCidrAddress = peerInterface.getIpAddress().getHostAddress()
809 + "/32";
810 String peerCidrAddress = bgpPeer.getIpAddress().getHostAddress()
811 + "/32";
Jonathan Hart38c84932013-08-10 17:49:27 +1200812
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200813 //Common match fields
814 forwardMatchSrc.setDataLayerType(Ethernet.TYPE_IPv4);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200815 forwardMatchSrc.setNetworkProtocol(IPv4.PROTOCOL_TCP);
Jonathan Hart1912afc2013-10-11 12:02:44 +1300816 //forwardMatchSrc.setTransportDestination(BGP_PORT);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200817 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_IN_PORT
818 & ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
819
820
821 OFMatch reverseMatchSrc = forwardMatchSrc.clone();
822
823 forwardMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_SRC);
824 forwardMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
825
826 OFMatch forwardMatchDst = forwardMatchSrc.clone();
827
828 forwardMatchSrc.setTransportSource(BGP_PORT);
829 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
830 forwardMatchDst.setTransportDestination(BGP_PORT);
831 forwardMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
832
833 reverseMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
834 reverseMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_DST);
835
836 OFMatch reverseMatchDst = reverseMatchSrc.clone();
837
838 reverseMatchSrc.setTransportSource(BGP_PORT);
839 reverseMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
840 reverseMatchDst.setTransportDestination(BGP_PORT);
841 reverseMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
842
843 fm.setMatch(forwardMatchSrc);
844
Jonathan Hart38c84932013-08-10 17:49:27 +1200845 OFMatch forwardIcmpMatch = new OFMatch();
846 forwardIcmpMatch.setDataLayerType(Ethernet.TYPE_IPv4);
847 forwardIcmpMatch.setNetworkProtocol(IPv4.PROTOCOL_ICMP);
848 forwardIcmpMatch.setWildcards(forwardIcmpMatch.getWildcards() &
849 ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
850
851 OFMatch reverseIcmpMatch = forwardIcmpMatch.clone();
852 forwardIcmpMatch.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
853 reverseIcmpMatch.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
854
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200855 for (FlowEntry flowEntry : path.flowEntries()){
856 OFFlowMod forwardFlowModSrc, forwardFlowModDst;
857 OFFlowMod reverseFlowModSrc, reverseFlowModDst;
Jonathan Hart38c84932013-08-10 17:49:27 +1200858 OFFlowMod forwardIcmp, reverseIcmp;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200859 try {
860 forwardFlowModSrc = fm.clone();
861 forwardFlowModDst = fm.clone();
862 reverseFlowModSrc = fm.clone();
863 reverseFlowModDst = fm.clone();
Jonathan Hart38c84932013-08-10 17:49:27 +1200864 forwardIcmp = fm.clone();
865 reverseIcmp = fm.clone();
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200866 } catch (CloneNotSupportedException e) {
867 log.warn("Clone failed", e);
868 continue;
869 }
870
871 forwardMatchSrc.setInputPort(flowEntry.inPort().value());
872 forwardFlowModSrc.setMatch(forwardMatchSrc);
873 ((OFActionOutput)forwardFlowModSrc.getActions().get(0))
874 .setPort(flowEntry.outPort().value());
875
876 forwardMatchDst.setInputPort(flowEntry.inPort().value());
877 forwardFlowModDst.setMatch(forwardMatchDst);
878 ((OFActionOutput)forwardFlowModDst.getActions().get(0))
879 .setPort(flowEntry.outPort().value());
880
881 reverseMatchSrc.setInputPort(flowEntry.outPort().value());
882 reverseFlowModSrc.setMatch(reverseMatchSrc);
883 ((OFActionOutput)reverseFlowModSrc.getActions().get(0))
884 .setPort(flowEntry.inPort().value());
885
886 reverseMatchDst.setInputPort(flowEntry.outPort().value());
887 reverseFlowModDst.setMatch(reverseMatchDst);
888 ((OFActionOutput)reverseFlowModDst.getActions().get(0))
889 .setPort(flowEntry.inPort().value());
890
Jonathan Hart38c84932013-08-10 17:49:27 +1200891 ((OFActionOutput)forwardIcmp.getActions().get(0))
892 .setPort(flowEntry.outPort().value());
893 forwardIcmp.setMatch(forwardIcmpMatch);
894
895 ((OFActionOutput)reverseIcmp.getActions().get(0))
896 .setPort(flowEntry.inPort().value());
897 reverseIcmp.setMatch(reverseIcmpMatch);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200898
Jonathan Hart1912afc2013-10-11 12:02:44 +1300899 List<OFFlowMod> flowModList = new ArrayList<OFFlowMod>(6);
900 flowModList.add(forwardFlowModSrc);
901 flowModList.add(forwardFlowModDst);
902 flowModList.add(reverseFlowModSrc);
903 flowModList.add(reverseFlowModDst);
904 flowModList.add(forwardIcmp);
905 flowModList.add(reverseIcmp);
906 flowCache.write(flowEntry.dpid().value(), flowModList);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200907 }
908 }
909 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200910
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200911 @Override
Jonathan Hartabad6a52013-09-30 18:17:21 +1300912 public void arpResponse(InetAddress ipAddress, MACAddress macAddress) {
913 log.debug("Received ARP response: {} => {}",
914 ipAddress.getHostAddress(), macAddress);
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200915
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200916 /*
917 * We synchronize on this to prevent changes to the ptree while we're pushing
918 * flows to the switches. If the ptree changes, the ptree and switches
919 * could get out of sync.
920 */
921 synchronized (this) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200922 Path path = pathsWaitingOnArp.remove(ipAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200923
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200924 if (path != null) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200925 log.debug("Pushing path to {} at {} on {}", new Object[] {
Jonathan Hartabad6a52013-09-30 18:17:21 +1300926 path.getDstIpAddress().getHostAddress(), macAddress,
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200927 path.getDstInterface().getSwitchPort()});
928 //These paths should always be to BGP peers. Paths to non-peers are
929 //handled once the first prefix is ready to push
930 if (pushedPaths.containsKey(path.getDstInterface())) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200931 //A path already got pushed to this endpoint while we were waiting
932 //for ARP. We'll copy over the permanent attribute if it is set on this path.
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200933 if (path.isPermanent()) {
934 pushedPaths.get(path.getDstInterface()).setPermanent();
Jonathan Hart309889c2013-08-13 23:26:24 +1200935 }
936 }
937 else {
Jonathan Hartabad6a52013-09-30 18:17:21 +1300938 calculateAndPushPath(path, macAddress);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200939 pushedPaths.put(path.getDstIpAddress(), path);
Jonathan Hart309889c2013-08-13 23:26:24 +1200940 }
941 }
942
Jonathan Hart309889c2013-08-13 23:26:24 +1200943 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
944
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200945 for (RibUpdate update : prefixesToPush) {
946 //These will always be adds
947
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200948 RibEntry rib = ptree.lookup(update.getPrefix());
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200949 if (rib != null && rib.equals(update.getRibEntry())) {
950 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200951 rib.getNextHop().getHostAddress());
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200952 //We only push prefix flows if the prefix is still in the ptree
953 //and the next hop is the same as our update. The prefix could
954 //have been removed while we were waiting for the ARP, or the
955 //next hop could have changed.
Jonathan Hart309889c2013-08-13 23:26:24 +1200956 _processRibAdd(update);
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200957 } else {
958 log.debug("Received ARP response, but {},{} is no longer in ptree",
959 update.getPrefix(), update.getRibEntry());
960 }
961 }
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200962 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200963 }
964
Jonathan Hartc82051c2013-08-24 15:12:20 +1200965 private void setupArpFlows() {
966 OFMatch match = new OFMatch();
967 match.setDataLayerType(Ethernet.TYPE_ARP);
968 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
969
970 OFFlowMod fm = new OFFlowMod();
971 fm.setMatch(match);
972
973 OFActionOutput action = new OFActionOutput();
974 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
975 action.setMaxLength((short)0xffff);
976 List<OFAction> actions = new ArrayList<OFAction>(1);
977 actions.add(action);
978 fm.setActions(actions);
979
980 fm.setIdleTimeout((short)0)
981 .setHardTimeout((short)0)
982 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
983 .setCookie(0)
984 .setCommand(OFFlowMod.OFPFC_ADD)
985 .setPriority(ARP_PRIORITY)
986 .setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
987
988 for (String strdpid : switches){
Jonathan Hart1912afc2013-10-11 12:02:44 +1300989 flowCache.write(HexString.toLong(strdpid), fm);
Jonathan Hartc82051c2013-08-24 15:12:20 +1200990 }
991 }
992
Jonathan Hartf886fa12013-09-18 14:46:29 +1200993 private void setupDefaultDropFlows() {
994 OFFlowMod fm = new OFFlowMod();
995 fm.setMatch(new OFMatch());
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +1200996 fm.setActions(new ArrayList<OFAction>()); //No action means drop
Jonathan Hartf886fa12013-09-18 14:46:29 +1200997
998 fm.setIdleTimeout((short)0)
999 .setHardTimeout((short)0)
1000 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1001 .setCookie(0)
1002 .setCommand(OFFlowMod.OFPFC_ADD)
1003 .setPriority((short)0)
1004 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
1005
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001006 OFFlowMod fmLLDP;
1007 OFFlowMod fmBDDP;
1008 try {
1009 fmLLDP = fm.clone();
1010 fmBDDP = fm.clone();
1011 } catch (CloneNotSupportedException e1) {
1012 log.error("Error cloning flow mod", e1);
1013 return;
1014 }
1015
1016 OFMatch matchLLDP = new OFMatch();
1017 matchLLDP.setDataLayerType((short)0x8942);
1018 matchLLDP.setWildcards(matchLLDP.getWildcards() & ~ OFMatch.OFPFW_DL_TYPE);
1019 fmLLDP.setMatch(matchLLDP);
1020
1021 OFMatch matchBDDP = new OFMatch();
1022 matchBDDP.setDataLayerType((short)0x88cc);
1023 matchBDDP.setWildcards(matchBDDP.getWildcards() & ~ OFMatch.OFPFW_DL_TYPE);
1024 fmBDDP.setMatch(matchBDDP);
1025
1026 OFActionOutput action = new OFActionOutput();
1027 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1028 action.setMaxLength((short)0xffff);
1029 List<OFAction> actions = new ArrayList<OFAction>(1);
1030 actions.add(action);
1031
1032 fmLLDP.setActions(actions);
1033 fmBDDP.setActions(actions);
1034
1035 fmLLDP.setPriority(ARP_PRIORITY);
1036 fmLLDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1037 fmBDDP.setPriority(ARP_PRIORITY);
1038 fmBDDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1039
Jonathan Hart1912afc2013-10-11 12:02:44 +13001040 List<OFFlowMod> flowModList = new ArrayList<OFFlowMod>(3);
1041 flowModList.add(fm);
1042 flowModList.add(fmLLDP);
1043 flowModList.add(fmBDDP);
1044
Jonathan Hartf886fa12013-09-18 14:46:29 +12001045 for (String strdpid : switches){
Jonathan Hart1912afc2013-10-11 12:02:44 +13001046 flowCache.write(HexString.toLong(strdpid), flowModList);
Jonathan Hartf886fa12013-09-18 14:46:29 +12001047 }
1048 }
1049
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001050 private void beginRouting(){
1051 log.debug("Topology is now ready, beginning routing function");
Pavlin Radoslavov15954d42013-10-19 15:29:04 -07001052 topology = topologyNetService.newDatabaseTopology();
Jonathan Hartdefa44d2013-08-15 19:51:13 +12001053
Jonathan Hartc82051c2013-08-24 15:12:20 +12001054 setupArpFlows();
Jonathan Hartf886fa12013-09-18 14:46:29 +12001055 setupDefaultDropFlows();
Jonathan Hartc82051c2013-08-24 15:12:20 +12001056
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001057 setupBgpPaths();
Jonathan Hart98957bf2013-07-01 14:49:24 +12001058 setupFullMesh();
Jonathan Harte7694532013-09-12 12:34:46 +12001059
1060 //Suppress link discovery on external-facing router ports
1061 for (Interface intf : interfaces.values()) {
1062 linkDiscoveryService.AddToSuppressLLDPs(intf.getDpid(), intf.getPort());
1063 }
1064
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001065 bgpUpdatesExecutor.execute(new Runnable() {
1066 @Override
1067 public void run() {
1068 doUpdatesThread();
1069 }
1070 });
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001071 }
1072
1073 private void checkSwitchesConnected(){
1074 for (String dpid : switches){
1075 if (floodlightProvider.getSwitches().get(HexString.toLong(dpid)) == null){
1076 log.debug("Not all switches are here yet");
1077 return;
1078 }
1079 }
1080 switchesConnected = true;
1081 }
1082
Jonathan Hartc824ad02013-07-03 15:58:45 +12001083 //Actually we only need to go half way round to verify full mesh connectivity
1084 //(n^2)/2
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001085 private void checkTopologyReady(){
Jonathan Hartc824ad02013-07-03 15:58:45 +12001086 for (Interface dstInterface : interfaces.values()) {
1087 for (Interface srcInterface : interfaces.values()) {
Jonathan Hart45107222013-10-22 17:35:04 -07001088 if (dstInterface.equals(srcInterface)) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001089 continue;
1090 }
1091
Pavlin Radoslavov15954d42013-10-19 15:29:04 -07001092 DataPath shortestPath = topologyNetService.getDatabaseShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +12001093 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001094
1095 if (shortestPath == null){
1096 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +12001097 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001098 return;
1099 }
1100 }
1101 }
1102 topologyReady = true;
1103 }
1104
1105 private void checkStatus(){
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001106 if (!switchesConnected){
1107 checkSwitchesConnected();
1108 }
1109 boolean oldTopologyReadyStatus = topologyReady;
1110 if (switchesConnected && !topologyReady){
1111 checkTopologyReady();
1112 }
1113 if (!oldTopologyReadyStatus && topologyReady){
1114 beginRouting();
1115 }
1116 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001117
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001118 private void doUpdatesThread() {
1119 boolean interrupted = false;
1120 try {
1121 while (true) {
1122 try {
1123 RibUpdate update = ribUpdates.take();
1124 switch (update.getOperation()){
1125 case UPDATE:
Jonathan Harte4c98692013-10-18 17:40:03 -07001126 if (validateUpdate(update)) {
1127 processRibAdd(update);
1128 }
1129 else {
1130 log.debug("Rib UPDATE out of order: {} via {}",
1131 update.getPrefix(), update.getRibEntry().getNextHop());
1132 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001133 break;
1134 case DELETE:
Jonathan Harte4c98692013-10-18 17:40:03 -07001135 if (validateUpdate(update)) {
1136 processRibDelete(update);
1137 }
1138 else {
1139 log.debug("Rib DELETE out of order: {} via {}",
1140 update.getPrefix(), update.getRibEntry().getNextHop());
1141 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001142 break;
1143 }
1144 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001145 log.debug("Interrupted while taking from updates queue", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001146 interrupted = true;
Jonathan Hart309889c2013-08-13 23:26:24 +12001147 } catch (Exception e) {
1148 log.debug("exception", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001149 }
1150 }
1151 } finally {
1152 if (interrupted) {
1153 Thread.currentThread().interrupt();
1154 }
1155 }
1156 }
Jonathan Harte4c98692013-10-18 17:40:03 -07001157
1158 private boolean validateUpdate(RibUpdate update) {
1159 RibEntry newEntry = update.getRibEntry();
1160 RibEntry oldEntry = ptree.lookup(update.getPrefix());
1161
1162 //If there is no existing entry we must assume this is the most recent
1163 //update. However this might not always be the case as we might have a
1164 //POST then DELETE reordering.
1165 //if (oldEntry == null || !newEntry.getNextHop().equals(oldEntry.getNextHop())) {
1166 if (oldEntry == null) {
1167 return true;
1168 }
1169
1170 // This handles the case where routes are gathered in the initial
1171 // request because they don't have sequence number info
1172 if (newEntry.getSysUpTime() == -1 && newEntry.getSequenceNum() == -1) {
1173 return true;
1174 }
1175
1176 if (newEntry.getSysUpTime() > oldEntry.getSysUpTime()) {
1177 return true;
1178 }
1179 else if (newEntry.getSysUpTime() == oldEntry.getSysUpTime()) {
1180 if (newEntry.getSequenceNum() > oldEntry.getSequenceNum()) {
1181 return true;
1182 }
1183 else {
1184 return false;
1185 }
1186 }
1187 else {
1188 return false;
1189 }
1190 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001191
1192 @Override
Jonathan Hart64c0b202013-08-20 15:45:07 +12001193 public void topologyChanged() {
1194 if (topologyReady) {
1195 return;
1196 }
1197
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001198 boolean refreshNeeded = false;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -07001199 for (LDUpdate ldu : topologyService.getLastLinkUpdates()){
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001200 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1201 //We don't need to recalculate anything for just link updates
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001202 //They happen very frequently
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001203 refreshNeeded = true;
1204 }
Jonathan Hart98957bf2013-07-01 14:49:24 +12001205
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001206 log.debug("Topo change {}", ldu.getOperation());
Jonathan Hartc824ad02013-07-03 15:58:45 +12001207
Jonathan Hart98957bf2013-07-01 14:49:24 +12001208 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1209 synchronized (linkUpdates) {
1210 linkUpdates.add(ldu);
1211 }
1212 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001213 }
1214
Jonathan Hart64c0b202013-08-20 15:45:07 +12001215 if (refreshNeeded && !topologyReady){
Jonathan Hart98957bf2013-07-01 14:49:24 +12001216 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
pingping-lina2cbfad2013-03-07 08:39:21 +08001217 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001218 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001219
1220 @Override
1221 public void addedSwitch(IOFSwitch sw) {
1222 if (!topologyReady) {
1223 sw.clearAllFlowMods();
1224 }
Jonathan Hart1912afc2013-10-11 12:02:44 +13001225
1226 flowCache.switchConnected(sw);
Jonathan Hart64c0b202013-08-20 15:45:07 +12001227 }
1228
1229 @Override
Jonathan Hart08ee8522013-09-22 17:34:43 +12001230 public void removedSwitch(IOFSwitch sw) {}
Jonathan Hart64c0b202013-08-20 15:45:07 +12001231
1232 @Override
Jonathan Hart08ee8522013-09-22 17:34:43 +12001233 public void switchPortChanged(Long switchId) {}
Jonathan Hart64c0b202013-08-20 15:45:07 +12001234
1235 @Override
1236 public String getName() {
Jonathan Hart08ee8522013-09-22 17:34:43 +12001237 return "BgpRoute";
1238 }
1239
1240 /*
1241 * ILayer3InfoService methods
1242 */
1243
1244 @Override
1245 public boolean isInterfaceAddress(InetAddress address) {
1246 Interface intf = interfacePtrie.match(new Prefix(address.getAddress(), 32));
1247 return (intf != null && intf.getIpAddress().equals(address));
1248 }
1249
1250 @Override
1251 public boolean inConnectedNetwork(InetAddress address) {
1252 Interface intf = interfacePtrie.match(new Prefix(address.getAddress(), 32));
1253 return (intf != null && !intf.getIpAddress().equals(address));
1254 }
1255
1256 @Override
1257 public boolean fromExternalNetwork(long inDpid, short inPort) {
1258 for (Interface intf : interfaces.values()) {
1259 if (intf.getDpid() == inDpid && intf.getPort() == inPort) {
1260 return true;
1261 }
1262 }
1263 return false;
1264 }
1265
1266 @Override
1267 public Interface getOutgoingInterface(InetAddress dstIpAddress) {
1268 return interfacePtrie.match(new Prefix(dstIpAddress.getAddress(), 32));
1269 }
1270
1271 @Override
1272 public boolean hasLayer3Configuration() {
1273 return !interfaces.isEmpty();
1274 }
1275
1276 @Override
1277 public MACAddress getRouterMacAddress() {
1278 return bgpdMacAddress;
Jonathan Hart64c0b202013-08-20 15:45:07 +12001279 }
Jonathan Hart5afde492013-10-01 12:30:53 +13001280
1281 /*
1282 * TODO This is a hack to get the REST API to work for ProxyArpManager.
1283 * The REST API is currently tied to the Floodlight module system and we
1284 * need to separate it to allow ONOS modules to use it. For now we will
1285 * proxy calls through to the ProxyArpManager (which is not a Floodlight
1286 * module) through this class which is a module.
1287 */
1288 @Override
1289 public MACAddress getMacAddress(InetAddress ipAddress) {
1290 return proxyArp.getMacAddress(ipAddress);
1291 }
1292
1293 @Override
1294 public void sendArpRequest(InetAddress ipAddress, IArpRequester requester,
1295 boolean retry) {
1296 proxyArp.sendArpRequest(ipAddress, requester, retry);
1297 }
1298
1299 @Override
1300 public List<String> getMappings() {
1301 return proxyArp.getMappings();
1302 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001303}