blob: 00ee1fca43a652eb2e7b5d0eb6365b2102d4f0dd [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;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070037import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoRouteService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120038import net.onrc.onos.ofcontroller.core.internal.TopoLinkServiceImpl;
HIGUCHI Yutaa56fbde2013-06-17 14:26:05 -070039import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery;
40import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery.LDUpdate;
Jonathan Harte7694532013-09-12 12:34:46 +120041import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscoveryService;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120042import net.onrc.onos.ofcontroller.proxyarp.IArpRequester;
Jonathan Hartc7ca35d2013-06-25 20:54:25 +120043import net.onrc.onos.ofcontroller.proxyarp.ProxyArpManager;
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -070044import net.onrc.onos.ofcontroller.routing.TopoRouteService;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070045import net.onrc.onos.ofcontroller.util.DataPath;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120046import net.onrc.onos.ofcontroller.util.Dpid;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070047import net.onrc.onos.ofcontroller.util.FlowEntry;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070048import net.onrc.onos.ofcontroller.util.Port;
49import net.onrc.onos.ofcontroller.util.SwitchPort;
pingping-line2a09ca2013-03-23 09:33:58 +080050import net.sf.json.JSONArray;
51import net.sf.json.JSONObject;
52import net.sf.json.JSONSerializer;
pingping-lina2cbfad2013-03-07 08:39:21 +080053
Jonathan Hartd1f23252013-06-13 15:17:05 +120054import org.codehaus.jackson.JsonParseException;
55import org.codehaus.jackson.map.JsonMappingException;
56import org.codehaus.jackson.map.ObjectMapper;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070057import org.openflow.protocol.OFFlowMod;
58import org.openflow.protocol.OFMatch;
59import org.openflow.protocol.OFMessage;
60import 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,
79 IOFSwitchListener {
pingping-lina2cbfad2013-03-07 08:39:21 +080080
81 protected static Logger log = LoggerFactory.getLogger(BgpRoute.class);
82
83 protected IFloodlightProviderService floodlightProvider;
84 protected ITopologyService topology;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070085 protected ITopoRouteService topoRouteService;
Jonathan Harte7694532013-09-12 12:34:46 +120086 protected ILinkDiscoveryService linkDiscoveryService;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070087 protected IRestApiService restApi;
88
Jonathan Hartc7ca35d2013-06-25 20:54:25 +120089 protected ProxyArpManager proxyArp;
90
Jonathan Hart29b972d2013-08-12 23:43:51 +120091 protected IPatriciaTrie<RibEntry> ptree;
Jonathan Hartabf10222013-08-13 10:19:34 +120092 protected IPatriciaTrie<Interface> interfacePtrie;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120093 protected BlockingQueue<RibUpdate> ribUpdates;
94
Jonathan Hart61ba9372013-05-19 20:10:29 -070095 protected String bgpdRestIp;
96 protected String routerId;
Jonathan Hart9575cb62013-07-05 13:43:49 +120097 protected String configFilename = "config.json";
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070098
99 //We need to identify our flows somehow. But like it says in LearningSwitch.java,
100 //the controller/OS should hand out cookie IDs to prevent conflicts.
101 protected final long APP_COOKIE = 0xa0000000000000L;
102 //Cookie for flows that do L2 forwarding within SDN domain to egress routers
103 protected final long L2_FWD_COOKIE = APP_COOKIE + 1;
104 //Cookie for flows in ingress switches that rewrite the MAC address
105 protected final long MAC_RW_COOKIE = APP_COOKIE + 2;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200106 //Cookie for flows that setup BGP paths
107 protected final long BGP_COOKIE = APP_COOKIE + 3;
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200108 //Forwarding uses priority 0, and the mac rewrite entries in ingress switches
109 //need to be higher priority than this otherwise the rewrite may not get done
110 protected final short SDNIP_PRIORITY = 10;
Jonathan Hartc82051c2013-08-24 15:12:20 +1200111 protected final short ARP_PRIORITY = 20;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700112
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200113 protected final short BGP_PORT = 179;
114
Jonathan Hart98957bf2013-07-01 14:49:24 +1200115 protected final int TOPO_DETECTION_WAIT = 2; //seconds
116
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200117 //Configuration stuff
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200118 protected List<String> switches;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200119 protected Map<String, Interface> interfaces;
Jonathan Hartc824ad02013-07-03 15:58:45 +1200120 protected Map<InetAddress, BgpPeer> bgpPeers;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200121 protected SwitchPort bgpdAttachmentPoint;
Jonathan Hart2f790d22013-08-15 14:01:24 +1200122 protected MACAddress bgpdMacAddress;
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200123
124 //True when all switches have connected
125 protected volatile boolean switchesConnected = false;
126 //True when we have a full mesh of shortest paths between gateways
127 protected volatile boolean topologyReady = false;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200128
Jonathan Hart98957bf2013-07-01 14:49:24 +1200129 protected ArrayList<LDUpdate> linkUpdates;
130 protected SingletonTask topologyChangeDetectorTask;
131
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200132 protected SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
Jonathan Hart309889c2013-08-13 23:26:24 +1200133
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200134 protected Map<InetAddress, Path> pathsWaitingOnArp;
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200135
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200136 protected ExecutorService bgpUpdatesExecutor;
137
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200138 protected Map<InetAddress, Path> pushedPaths;
139 protected Map<Prefix, Path> prefixToPath;
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200140 protected Multimap<Prefix, PushedFlowMod> pushedFlows;
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200141
142 protected volatile Map<Long, ?> topoRouteTopology = null;
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200143
Jonathan Hart98957bf2013-07-01 14:49:24 +1200144 protected class TopologyChangeDetector implements Runnable {
145 @Override
146 public void run() {
147 log.debug("Running topology change detection task");
148 synchronized (linkUpdates) {
Jonathan Hartc824ad02013-07-03 15:58:45 +1200149 //This is the model the REST API uses to retrieve network graph info
Jonathan Hart98957bf2013-07-01 14:49:24 +1200150 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
151
152 List<Link> activeLinks = topoLinkService.getActiveLinks();
Jonathan Hart98957bf2013-07-01 14:49:24 +1200153
154 Iterator<LDUpdate> it = linkUpdates.iterator();
155 while (it.hasNext()){
156 LDUpdate ldu = it.next();
157 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
158 ldu.getDst(), ldu.getDstPort());
159
160 if (activeLinks.contains(l)){
161 log.debug("Not found: {}", l);
162 it.remove();
163 }
164 }
165 }
166
Jonathan Hart64c0b202013-08-20 15:45:07 +1200167 if (!topologyReady) {
168 if (linkUpdates.isEmpty()){
169 //All updates have been seen in network map.
170 //We can check if topology is ready
171 log.debug("No known changes outstanding. Checking topology now");
172 checkStatus();
173 }
174 else {
175 //We know of some link updates that haven't propagated to the database yet
176 log.debug("Some changes not found in network map - {} links missing", linkUpdates.size());
177 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
178 }
Jonathan Hart98957bf2013-07-01 14:49:24 +1200179 }
180 }
181 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700182
Jonathan Hartd1f23252013-06-13 15:17:05 +1200183 private void readGatewaysConfiguration(String gatewaysFilename){
184 File gatewaysFile = new File(gatewaysFilename);
185 ObjectMapper mapper = new ObjectMapper();
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700186
Jonathan Hartd1f23252013-06-13 15:17:05 +1200187 try {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200188 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
189
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200190 switches = config.getSwitches();
Jonathan Hart9575cb62013-07-05 13:43:49 +1200191 interfaces = new HashMap<String, Interface>();
192 for (Interface intf : config.getInterfaces()){
193 interfaces.put(intf.getName(), intf);
194 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200195 bgpPeers = new HashMap<InetAddress, BgpPeer>();
196 for (BgpPeer peer : config.getPeers()){
197 bgpPeers.put(peer.getIpAddress(), peer);
198 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200199
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200200 bgpdAttachmentPoint = new SwitchPort(
201 new Dpid(config.getBgpdAttachmentDpid()),
202 new Port(config.getBgpdAttachmentPort()));
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200203
Jonathan Hart2f790d22013-08-15 14:01:24 +1200204 bgpdMacAddress = config.getBgpdMacAddress();
Jonathan Hartd1f23252013-06-13 15:17:05 +1200205 } catch (JsonParseException e) {
206 log.error("Error in JSON file", e);
207 System.exit(1);
208 } catch (JsonMappingException e) {
209 log.error("Error in JSON file", e);
210 System.exit(1);
211 } catch (IOException e) {
212 log.error("Error reading JSON file", e);
213 System.exit(1);
214 }
Jonathan Hartabf10222013-08-13 10:19:34 +1200215
216 //Populate the interface Patricia Trie
217 for (Interface intf : interfaces.values()) {
218 Prefix prefix = new Prefix(intf.getIpAddress().getAddress(), intf.getPrefixLength());
219 interfacePtrie.put(prefix, intf);
220 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700221 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800222
223 @Override
224 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700225 Collection<Class<? extends IFloodlightService>> l
226 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800227 l.add(IBgpRouteService.class);
228 return l;
229 }
230
231 @Override
232 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700233 Map<Class<? extends IFloodlightService>, IFloodlightService> m
234 = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
pingping-line2a09ca2013-03-23 09:33:58 +0800235 m.put(IBgpRouteService.class, this);
pingping-lina2cbfad2013-03-07 08:39:21 +0800236 return m;
237 }
238
pingping-lina2cbfad2013-03-07 08:39:21 +0800239 @Override
240 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700241 Collection<Class<? extends IFloodlightService>> l
242 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800243 l.add(IFloodlightProviderService.class);
244 l.add(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700245 l.add(IRestApiService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800246 return l;
247 }
248
249 @Override
250 public void init(FloodlightModuleContext context)
251 throws FloodlightModuleException {
252
Jonathan Hart29b972d2013-08-12 23:43:51 +1200253 ptree = new PatriciaTrie<RibEntry>(32);
Jonathan Hartabf10222013-08-13 10:19:34 +1200254 interfacePtrie = new PatriciaTrie<Interface>(32);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200255
256 ribUpdates = new LinkedBlockingQueue<RibUpdate>();
Jonathan Hartc824ad02013-07-03 15:58:45 +1200257
pingping-lina2cbfad2013-03-07 08:39:21 +0800258 // Register floodlight provider and REST handler.
259 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800260 topology = context.getServiceImpl(ITopologyService.class);
Jonathan Harte7694532013-09-12 12:34:46 +1200261 linkDiscoveryService = context.getServiceImpl(ILinkDiscoveryService.class);
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200262 restApi = context.getServiceImpl(IRestApiService.class);
263
264 //TODO We'll initialise this here for now, but it should really be done as
265 //part of the controller core
Jonathan Hart2f790d22013-08-15 14:01:24 +1200266 proxyArp = new ProxyArpManager(floodlightProvider, topology);
pingping-lina2cbfad2013-03-07 08:39:21 +0800267
Jonathan Hart98957bf2013-07-01 14:49:24 +1200268 linkUpdates = new ArrayList<LDUpdate>();
269 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
270 topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700271
272 topoRouteService = new TopoRouteService("");
Jonathan Hart98957bf2013-07-01 14:49:24 +1200273
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200274 pathsWaitingOnArp = new HashMap<InetAddress, Path>();
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200275 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
276 HashMultimap.<InetAddress, RibUpdate>create());
277
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200278 pushedPaths = new HashMap<InetAddress, Path>();
279 prefixToPath = new HashMap<Prefix, Path>();
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200280 pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
281
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200282 bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
283 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
284
Jonathan Hart61ba9372013-05-19 20:10:29 -0700285 //Read in config values
286 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
287 if (bgpdRestIp == null){
288 log.error("BgpdRestIp property not found in config file");
289 System.exit(1);
290 }
291 else {
292 log.info("BgpdRestIp set to {}", bgpdRestIp);
293 }
294
295 routerId = context.getConfigParams(this).get("RouterId");
296 if (routerId == null){
297 log.error("RouterId property not found in config file");
298 System.exit(1);
299 }
300 else {
301 log.info("RouterId set to {}", routerId);
302 }
Jonathan Hartd1f23252013-06-13 15:17:05 +1200303
Jonathan Hart9575cb62013-07-05 13:43:49 +1200304 String configFilenameParameter = context.getConfigParams(this).get("configfile");
305 if (configFilenameParameter != null){
306 configFilename = configFilenameParameter;
307 }
308 log.debug("Config file set to {}", configFilename);
309
310 readGatewaysConfiguration(configFilename);
Jonathan Hart2f790d22013-08-15 14:01:24 +1200311
Jonathan Hart1633a402013-08-24 11:38:56 +1200312 proxyArp.setL3Mode(interfacePtrie, interfaces.values(), bgpdMacAddress);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200313 }
314
315 @Override
316 public void startUp(FloodlightModuleContext context) {
317 restApi.addRestletRoutable(new BgpRouteWebRoutable());
318 topology.addListener(this);
Jonathan Hart64c0b202013-08-20 15:45:07 +1200319 floodlightProvider.addOFSwitchListener(this);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200320
Jonathan Hart2f790d22013-08-15 14:01:24 +1200321 proxyArp.startUp();
322
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200323 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, proxyArp);
324
325 //Retrieve the RIB from BGPd during startup
326 retrieveRib();
pingping-lina2cbfad2013-03-07 08:39:21 +0800327 }
328
Jonathan Hart29b972d2013-08-12 23:43:51 +1200329 public IPatriciaTrie<RibEntry> getPtree() {
pingping-lina2cbfad2013-03-07 08:39:21 +0800330 return ptree;
331 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700332
333 public void clearPtree() {
Jonathan Hart29b972d2013-08-12 23:43:51 +1200334 ptree = new PatriciaTrie<RibEntry>(32);
pingping-line2a09ca2013-03-23 09:33:58 +0800335 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700336
pingping-line2a09ca2013-03-23 09:33:58 +0800337 public String getBGPdRestIp() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700338 return bgpdRestIp;
pingping-line2a09ca2013-03-23 09:33:58 +0800339 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700340
pingping-line2a09ca2013-03-23 09:33:58 +0800341 public String getRouterId() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700342 return routerId;
pingping-line2a09ca2013-03-23 09:33:58 +0800343 }
pingping-lina2cbfad2013-03-07 08:39:21 +0800344
Jonathan Hart61ba9372013-05-19 20:10:29 -0700345 private void retrieveRib(){
346 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
347 String response = RestClient.get(url);
348
349 if (response.equals("")){
350 return;
351 }
352
353 response = response.replaceAll("\"", "'");
354 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
355 JSONArray rib_json_array = jsonObj.getJSONArray("rib");
356 String router_id = jsonObj.getString("router-id");
357
358 int size = rib_json_array.size();
359
360 log.info("Retrived RIB of {} entries from BGPd", size);
361
362 for (int j = 0; j < size; j++) {
363 JSONObject second_json_object = rib_json_array.getJSONObject(j);
364 String prefix = second_json_object.getString("prefix");
365 String nexthop = second_json_object.getString("nexthop");
366
367 //insert each rib entry into the local rib;
368 String[] substring = prefix.split("/");
369 String prefix1 = substring[0];
370 String mask1 = substring[1];
371
372 Prefix p;
373 try {
374 p = new Prefix(prefix1, Integer.valueOf(mask1));
375 } catch (NumberFormatException e) {
376 log.warn("Wrong mask format in RIB JSON: {}", mask1);
377 continue;
Jonathan Hart32e18222013-08-07 22:05:42 +1200378 } catch (IllegalArgumentException e1) {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700379 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
380 continue;
381 }
382
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200383 RibEntry rib = new RibEntry(router_id, nexthop);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200384
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200385 try {
386 ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
387 } catch (InterruptedException e) {
388 log.debug("Interrupted while pushing onto update queue");
389 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700390 }
391 }
392
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200393 @Override
394 public void newRibUpdate(RibUpdate update) {
Jonathan Hart9ea31212013-08-12 21:40:34 +1200395 try {
396 ribUpdates.put(update);
397 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200398 log.debug("Interrupted while putting on ribUpdates queue", e);
399 Thread.currentThread().interrupt();
Jonathan Hart9ea31212013-08-12 21:40:34 +1200400 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200401 }
402
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200403 public synchronized void processRibAdd(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200404 Prefix prefix = update.getPrefix();
405
Jonathan Hart9ea31212013-08-12 21:40:34 +1200406 log.debug("Processing prefix add {}", prefix);
407
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200408 RibEntry rib = ptree.put(prefix, update.getRibEntry());
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200409
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200410 if (rib != null && !rib.equals(update.getRibEntry())) {
Jonathan Hart2f740782013-08-04 00:49:21 +1200411 //There was an existing nexthop for this prefix. This update supersedes that,
412 //so we need to remove the old flows for this prefix from the switches
Jonathan Hart309889c2013-08-13 23:26:24 +1200413 _processDeletePrefix(prefix, rib);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200414 }
Jonathan Hart2f740782013-08-04 00:49:21 +1200415
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200416 if (update.getRibEntry().getNextHop().equals(
417 InetAddresses.forString("0.0.0.0"))) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200418 //Route originated by SDN domain
419 //We don't handle these at the moment
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200420 log.debug("Own route {} to {}", prefix,
421 update.getRibEntry().getNextHop().getHostAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200422 return;
423 }
424
425 _processRibAdd(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200426 }
427
Jonathan Hart309889c2013-08-13 23:26:24 +1200428 private void _processRibAdd(RibUpdate update) {
429 Prefix prefix = update.getPrefix();
430 RibEntry rib = update.getRibEntry();
431
432 InetAddress dstIpAddress = rib.getNextHop();
433
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200434 //See if we know the MAC address of the next hop
Jonathan Hart309889c2013-08-13 23:26:24 +1200435 byte[] nextHopMacAddress = proxyArp.getMacAddress(rib.getNextHop());
Jonathan Hart309889c2013-08-13 23:26:24 +1200436
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200437 //Find the attachment point (egress interface) of the next hop
438 Interface egressInterface = null;
Jonathan Hart309889c2013-08-13 23:26:24 +1200439 if (bgpPeers.containsKey(dstIpAddress)) {
440 //Route to a peer
441 log.debug("Route to peer {}", dstIpAddress);
442 BgpPeer peer = bgpPeers.get(dstIpAddress);
443 egressInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart309889c2013-08-13 23:26:24 +1200444 }
445 else {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200446 //Route to non-peer
Jonathan Hart309889c2013-08-13 23:26:24 +1200447 log.debug("Route to non-peer {}", dstIpAddress);
448 egressInterface = interfacePtrie.match(
449 new Prefix(dstIpAddress.getAddress(), 32));
450 if (egressInterface == null) {
451 log.warn("No outgoing interface found for {}", dstIpAddress.getHostAddress());
452 return;
453 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200454 }
455
456 if (nextHopMacAddress == null) {
457 prefixesWaitingOnArp.put(dstIpAddress,
458 new RibUpdate(Operation.UPDATE, prefix, rib));
459 proxyArp.sendArpRequest(dstIpAddress, this, true);
460 return;
461 }
462 else {
463 if (!bgpPeers.containsKey(dstIpAddress)) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200464 //If the prefix is for a non-peer we need to ensure there's a path,
465 //and push one if there isn't.
466 Path path = pushedPaths.get(dstIpAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200467 if (path == null) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200468 path = new Path(egressInterface, dstIpAddress);
469 setUpDataPath(path, MACAddress.valueOf(nextHopMacAddress));
Jonathan Hart309889c2013-08-13 23:26:24 +1200470 pushedPaths.put(dstIpAddress, path);
471 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200472
473 path.incrementUsers();
474 prefixToPath.put(prefix, path);
475 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200476
477 //For all prefixes we need to add the first-hop mac-rewriting flows
Jonathan Hart309889c2013-08-13 23:26:24 +1200478 addPrefixFlows(prefix, egressInterface, nextHopMacAddress);
479 }
480 }
481
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200482 private void addPrefixFlows(Prefix prefix, Interface egressInterface, byte[] nextHopMacAddress) {
483 log.debug("Adding flows for prefix {} added, next hop mac {}",
484 prefix, HexString.toHexString(nextHopMacAddress));
485
486 //Add a flow to rewrite mac for this prefix to all other border switches
487 for (Interface srcInterface : interfaces.values()) {
488 if (srcInterface == egressInterface) {
489 //Don't push a flow for the switch where this peer is attached
490 continue;
491 }
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200492
493
494 DataPath shortestPath;
495 if (topoRouteTopology == null) {
496 shortestPath = topoRouteService.getShortestPath(
497 srcInterface.getSwitchPort(),
498 egressInterface.getSwitchPort());
499 }
500 else {
501 shortestPath = topoRouteService.getTopoShortestPath(
502 topoRouteTopology, srcInterface.getSwitchPort(),
503 egressInterface.getSwitchPort());
504 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200505
506 if (shortestPath == null){
507 log.debug("Shortest path between {} and {} not found",
508 srcInterface.getSwitchPort(),
509 egressInterface.getSwitchPort());
510 return; // just quit here?
511 }
512
513 //Set up the flow mod
514 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
515 .getMessage(OFType.FLOW_MOD);
516
517 fm.setIdleTimeout((short)0)
518 .setHardTimeout((short)0)
519 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
520 .setCookie(MAC_RW_COOKIE)
521 .setCommand(OFFlowMod.OFPFC_ADD)
522 .setPriority(SDNIP_PRIORITY)
523 .setLengthU(OFFlowMod.MINIMUM_LENGTH
524 + OFActionDataLayerDestination.MINIMUM_LENGTH
525 + OFActionOutput.MINIMUM_LENGTH);
526
527 OFMatch match = new OFMatch();
528 match.setDataLayerType(Ethernet.TYPE_IPv4);
529 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
530
531 match.setFromCIDR(prefix.toString(), OFMatch.STR_NW_DST);
532 fm.setMatch(match);
533
534 //Set up MAC rewrite action
535 OFActionDataLayerDestination macRewriteAction = new OFActionDataLayerDestination();
536 macRewriteAction.setDataLayerAddress(nextHopMacAddress);
537
538 //Set up output action
539 OFActionOutput outputAction = new OFActionOutput();
540 outputAction.setMaxLength((short)0xffff);
541 Port outputPort = shortestPath.flowEntries().get(0).outPort();
542 outputAction.setPort(outputPort.value());
543
544 List<OFAction> actions = new ArrayList<OFAction>();
545 actions.add(macRewriteAction);
546 actions.add(outputAction);
547 fm.setActions(actions);
548
549 //Write to switch
550 IOFSwitch sw = floodlightProvider.getSwitches()
551 .get(srcInterface.getDpid());
552
553 if (sw == null){
554 log.warn("Switch not found when pushing flow mod");
555 continue;
556 }
557
558 pushedFlows.put(prefix, new PushedFlowMod(sw.getId(), fm));
559
560 List<OFMessage> msglist = new ArrayList<OFMessage>();
561 msglist.add(fm);
562 try {
563 sw.write(msglist, null);
564 sw.flush();
565 } catch (IOException e) {
566 log.error("Failure writing flow mod", e);
567 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200568 }
569 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200570
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200571 public synchronized void processRibDelete(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200572 Prefix prefix = update.getPrefix();
573
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200574 if (ptree.remove(prefix, update.getRibEntry())) {
575 /*
576 * Only delete flows if an entry was actually removed from the trie.
577 * If no entry was removed, the <prefix, nexthop> wasn't there so
578 * it's probably already been removed and we don't need to do anything
579 */
Jonathan Hart309889c2013-08-13 23:26:24 +1200580 _processDeletePrefix(prefix, update.getRibEntry());
Jonathan Hart309889c2013-08-13 23:26:24 +1200581 }
582 }
583
584 private void _processDeletePrefix(Prefix prefix, RibEntry ribEntry) {
585 deletePrefixFlows(prefix);
586
587 log.debug("Deleting {} to {}", prefix, ribEntry.getNextHop());
588 log.debug("is peer {}", bgpPeers.containsKey(ribEntry.getNextHop()));
589 if (!bgpPeers.containsKey(ribEntry.getNextHop())) {
590 log.debug("Getting path for route with non-peer nexthop");
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200591 //Path path = prefixToPath.get(prefix);
592 Path path = prefixToPath.remove(prefix);
Jonathan Hart309889c2013-08-13 23:26:24 +1200593
594 if (path == null) {
595 log.error("No path found for non-peer path");
596 }
597
598 path.decrementUsers();
599 log.debug("users {}, permanent {}", path.getUsers(), path.isPermanent());
600 if (path.getUsers() <= 0 && !path.isPermanent()) {
601 deletePath(path);
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200602 pushedPaths.remove(path.getDstIpAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200603 }
604 }
605 }
606
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200607 private void deletePrefixFlows(Prefix prefix) {
608 Collection<PushedFlowMod> pushedFlowMods
609 = pushedFlows.removeAll(prefix);
610
611 for (PushedFlowMod pfm : pushedFlowMods) {
612 log.debug("Pushing a DELETE flow mod to {}, matches prefix {} with mac-rewrite {}",
613 new Object[] {HexString.toHexString(pfm.getDpid()),
614 pfm.getFlowMod().getMatch().getNetworkDestination() +
615 pfm.getFlowMod().getMatch().getNetworkDestinationMaskLen(),
616 HexString.toHexString(((OFActionDataLayerDestination)pfm.getFlowMod().getActions().get(0))
617 .getDataLayerAddress())});
618
619 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
620 }
621 }
622
623 private void deletePath(Path path) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200624 for (PushedFlowMod pfm : path.getFlowMods()) {
625 log.debug("Pushing a DELETE flow mod to {}, dst MAC {}",
626 new Object[] {HexString.toHexString(pfm.getDpid()),
627 HexString.toHexString(pfm.getFlowMod().getMatch().getDataLayerDestination())
628 });
629
630 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
631 }
632 }
633
634 private void sendDeleteFlowMod(OFFlowMod addFlowMod, long dpid) {
635 addFlowMod.setCommand(OFFlowMod.OFPFC_DELETE_STRICT)
636 .setOutPort(OFPort.OFPP_NONE)
637 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
638
639 addFlowMod.getActions().clear();
640
641 IOFSwitch sw = floodlightProvider.getSwitches().get(dpid);
642 if (sw == null) {
643 log.warn("Switch not found when pushing delete flow mod");
644 return;
645 }
646
647 try {
648 sw.write(addFlowMod, null);
649 sw.flush();
650 } catch (IOException e) {
651 log.error("Failure writing flow mod", e);
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200652 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200653 }
654
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200655 //TODO test next-hop changes
Jonathan Hart2f740782013-08-04 00:49:21 +1200656 //TODO check delete/add synchronization
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200657
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700658 /*
659 * On startup we need to calculate a full mesh of paths between all gateway
660 * switches
661 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200662 private void setupFullMesh(){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700663 //For each border router, calculate and install a path from every other
664 //border switch to said border router. However, don't install the entry
665 //in to the first hop switch, as we need to install an entry to rewrite
666 //for each prefix received. This will be done later when prefixes have
667 //actually been received.
668
Jonathan Hartc824ad02013-07-03 15:58:45 +1200669 for (BgpPeer peer : bgpPeers.values()) {
670 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200671
Jonathan Hart309889c2013-08-13 23:26:24 +1200672 //We know there's not already a Path here pushed, because this is
673 //called before all other routing
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200674 Path path = new Path(peerInterface, peer.getIpAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200675 path.setPermanent();
676
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200677 //See if we know the MAC address of the peer. If not we can't
678 //do anything until we learn it
679 byte[] mac = proxyArp.getMacAddress(peer.getIpAddress());
680 if (mac == null) {
681 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
682 //Put in the pending paths list first
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200683 pathsWaitingOnArp.put(peer.getIpAddress(), path);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700684
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200685 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
686 continue;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700687 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200688
689 //If we know the MAC, lets go ahead and push the paths to this peer
Jonathan Hart309889c2013-08-13 23:26:24 +1200690 setUpDataPath(path, MACAddress.valueOf(mac));
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700691 }
692 }
693
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200694 private void setUpDataPath(Path path, MACAddress dstMacAddress) {
695 calculateAndPushPath(path, dstMacAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200696 }
697
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200698 private void calculateAndPushPath(Path path, MACAddress dstMacAddress) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200699 Interface dstInterface = path.getDstInterface();
700
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200701 log.debug("Setting up path to {}, {}", path.getDstIpAddress().getHostAddress(),
702 dstMacAddress);
703
Jonathan Hart309889c2013-08-13 23:26:24 +1200704 List<PushedFlowMod> pushedFlows = new ArrayList<PushedFlowMod>();
705
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200706 for (Interface srcInterface : interfaces.values()) {
707 if (dstInterface.equals(srcInterface.getName())){
708 continue;
709 }
710
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200711 DataPath shortestPath;
712 if (topoRouteTopology == null) {
713 log.debug("Using database topo");
714 shortestPath = topoRouteService.getShortestPath(
715 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
716 }
717 else {
718 log.debug("Using prepared topo");
719 shortestPath = topoRouteService.getTopoShortestPath(topoRouteTopology,
720 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
721 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200722
723 if (shortestPath == null){
724 log.debug("Shortest path between {} and {} not found",
725 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
726 return; // just quit here?
727 }
728
Jonathan Hart309889c2013-08-13 23:26:24 +1200729 pushedFlows.addAll(installPath(shortestPath.flowEntries(), dstMacAddress));
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200730 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200731
732 path.setFlowMods(pushedFlows);
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200733 }
734
Jonathan Hart309889c2013-08-13 23:26:24 +1200735 private List<PushedFlowMod> installPath(List<FlowEntry> flowEntries, MACAddress dstMacAddress){
736 List<PushedFlowMod> flowMods = new ArrayList<PushedFlowMod>();
737
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700738 //Set up the flow mod
739 OFFlowMod fm =
740 (OFFlowMod) floodlightProvider.getOFMessageFactory()
741 .getMessage(OFType.FLOW_MOD);
742
743 OFActionOutput action = new OFActionOutput();
744 action.setMaxLength((short)0xffff);
745 List<OFAction> actions = new ArrayList<OFAction>();
746 actions.add(action);
747
748 fm.setIdleTimeout((short)0)
749 .setHardTimeout((short)0)
750 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
751 .setCookie(L2_FWD_COOKIE)
752 .setCommand(OFFlowMod.OFPFC_ADD)
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700753 .setActions(actions)
754 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
755
756 //Don't push the first flow entry. We need to push entries in the
757 //first switch based on IP prefix which we don't know yet.
758 for (int i = 1; i < flowEntries.size(); i++){
759 FlowEntry flowEntry = flowEntries.get(i);
760
761 OFMatch match = new OFMatch();
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200762 match.setDataLayerDestination(dstMacAddress.toBytes());
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700763 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
764 ((OFActionOutput) fm.getActions().get(0)).setPort(flowEntry.outPort().value());
765
766 fm.setMatch(match);
767
768 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
769
770 if (sw == null){
771 log.warn("Switch not found when pushing flow mod");
772 continue;
773 }
774
Jonathan Hart309889c2013-08-13 23:26:24 +1200775 flowMods.add(new PushedFlowMod(sw.getId(), fm));
776
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700777 List<OFMessage> msglist = new ArrayList<OFMessage>();
778 msglist.add(fm);
779 try {
780 sw.write(msglist, null);
781 sw.flush();
782 } catch (IOException e) {
783 log.error("Failure writing flow mod", e);
784 }
785
786 try {
787 fm = fm.clone();
788 } catch (CloneNotSupportedException e1) {
789 log.error("Failure cloning flow mod", e1);
790 }
791 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200792
793 return flowMods;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700794 }
795
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200796 private void setupBgpPaths(){
Jonathan Hartc824ad02013-07-03 15:58:45 +1200797 for (BgpPeer bgpPeer : bgpPeers.values()){
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200798 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
799
800 DataPath path = topoRouteService.getShortestPath(
801 peerInterface.getSwitchPort(), bgpdAttachmentPoint);
802
803 if (path == null){
804 log.debug("Unable to compute path for BGP traffic for {}",
805 bgpPeer.getIpAddress());
806 continue;
807 }
808
809 //Set up the flow mod
810 OFFlowMod fm =
811 (OFFlowMod) floodlightProvider.getOFMessageFactory()
812 .getMessage(OFType.FLOW_MOD);
813
814 OFActionOutput action = new OFActionOutput();
815 action.setMaxLength((short)0xffff);
816 List<OFAction> actions = new ArrayList<OFAction>();
817 actions.add(action);
818
819 fm.setIdleTimeout((short)0)
820 .setHardTimeout((short)0)
821 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
822 .setCookie(BGP_COOKIE)
823 .setCommand(OFFlowMod.OFPFC_ADD)
824 .setPriority(SDNIP_PRIORITY)
825 .setActions(actions)
826 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
827
828 //Forward = gateway -> bgpd, reverse = bgpd -> gateway
829 OFMatch forwardMatchSrc = new OFMatch();
830
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200831 String interfaceCidrAddress = peerInterface.getIpAddress().getHostAddress()
832 + "/32";
833 String peerCidrAddress = bgpPeer.getIpAddress().getHostAddress()
834 + "/32";
Jonathan Hart38c84932013-08-10 17:49:27 +1200835
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200836 //Common match fields
837 forwardMatchSrc.setDataLayerType(Ethernet.TYPE_IPv4);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200838 forwardMatchSrc.setNetworkProtocol(IPv4.PROTOCOL_TCP);
839 forwardMatchSrc.setTransportDestination(BGP_PORT);
840 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_IN_PORT
841 & ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
842
843
844 OFMatch reverseMatchSrc = forwardMatchSrc.clone();
845
846 forwardMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_SRC);
847 forwardMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
848
849 OFMatch forwardMatchDst = forwardMatchSrc.clone();
850
851 forwardMatchSrc.setTransportSource(BGP_PORT);
852 forwardMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
853 forwardMatchDst.setTransportDestination(BGP_PORT);
854 forwardMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
855
856 reverseMatchSrc.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
857 reverseMatchSrc.setFromCIDR(peerCidrAddress, OFMatch.STR_NW_DST);
858
859 OFMatch reverseMatchDst = reverseMatchSrc.clone();
860
861 reverseMatchSrc.setTransportSource(BGP_PORT);
862 reverseMatchSrc.setWildcards(forwardMatchSrc.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
863 reverseMatchDst.setTransportDestination(BGP_PORT);
864 reverseMatchDst.setWildcards(forwardMatchDst.getWildcards() & ~OFMatch.OFPFW_TP_DST);
865
866 fm.setMatch(forwardMatchSrc);
867
Jonathan Hart38c84932013-08-10 17:49:27 +1200868 OFMatch forwardIcmpMatch = new OFMatch();
869 forwardIcmpMatch.setDataLayerType(Ethernet.TYPE_IPv4);
870 forwardIcmpMatch.setNetworkProtocol(IPv4.PROTOCOL_ICMP);
871 forwardIcmpMatch.setWildcards(forwardIcmpMatch.getWildcards() &
872 ~OFMatch.OFPFW_DL_TYPE & ~OFMatch.OFPFW_NW_PROTO);
873
874 OFMatch reverseIcmpMatch = forwardIcmpMatch.clone();
875 forwardIcmpMatch.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_DST);
876 reverseIcmpMatch.setFromCIDR(interfaceCidrAddress, OFMatch.STR_NW_SRC);
877
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200878 for (FlowEntry flowEntry : path.flowEntries()){
879 OFFlowMod forwardFlowModSrc, forwardFlowModDst;
880 OFFlowMod reverseFlowModSrc, reverseFlowModDst;
Jonathan Hart38c84932013-08-10 17:49:27 +1200881 OFFlowMod forwardIcmp, reverseIcmp;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200882 try {
883 forwardFlowModSrc = fm.clone();
884 forwardFlowModDst = fm.clone();
885 reverseFlowModSrc = fm.clone();
886 reverseFlowModDst = fm.clone();
Jonathan Hart38c84932013-08-10 17:49:27 +1200887 forwardIcmp = fm.clone();
888 reverseIcmp = fm.clone();
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200889 } catch (CloneNotSupportedException e) {
890 log.warn("Clone failed", e);
891 continue;
892 }
893
894 forwardMatchSrc.setInputPort(flowEntry.inPort().value());
895 forwardFlowModSrc.setMatch(forwardMatchSrc);
896 ((OFActionOutput)forwardFlowModSrc.getActions().get(0))
897 .setPort(flowEntry.outPort().value());
898
899 forwardMatchDst.setInputPort(flowEntry.inPort().value());
900 forwardFlowModDst.setMatch(forwardMatchDst);
901 ((OFActionOutput)forwardFlowModDst.getActions().get(0))
902 .setPort(flowEntry.outPort().value());
903
904 reverseMatchSrc.setInputPort(flowEntry.outPort().value());
905 reverseFlowModSrc.setMatch(reverseMatchSrc);
906 ((OFActionOutput)reverseFlowModSrc.getActions().get(0))
907 .setPort(flowEntry.inPort().value());
908
909 reverseMatchDst.setInputPort(flowEntry.outPort().value());
910 reverseFlowModDst.setMatch(reverseMatchDst);
911 ((OFActionOutput)reverseFlowModDst.getActions().get(0))
912 .setPort(flowEntry.inPort().value());
913
Jonathan Hart38c84932013-08-10 17:49:27 +1200914 ((OFActionOutput)forwardIcmp.getActions().get(0))
915 .setPort(flowEntry.outPort().value());
916 forwardIcmp.setMatch(forwardIcmpMatch);
917
918 ((OFActionOutput)reverseIcmp.getActions().get(0))
919 .setPort(flowEntry.inPort().value());
920 reverseIcmp.setMatch(reverseIcmpMatch);
921
922
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200923 IOFSwitch sw = floodlightProvider.getSwitches().get(flowEntry.dpid().value());
924
Jonathan Hart38c84932013-08-10 17:49:27 +1200925 if (sw == null) {
926 log.warn("Switch not found when pushing BGP paths");
927 return;
928 }
929
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200930 List<OFMessage> msgList = new ArrayList<OFMessage>(2);
931 msgList.add(forwardFlowModSrc);
932 msgList.add(forwardFlowModDst);
933 msgList.add(reverseFlowModSrc);
934 msgList.add(reverseFlowModDst);
Jonathan Hart38c84932013-08-10 17:49:27 +1200935 msgList.add(forwardIcmp);
936 msgList.add(reverseIcmp);
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200937
938 try {
939 sw.write(msgList, null);
940 sw.flush();
941 } catch (IOException e) {
942 log.error("Failure writing flow mod", e);
943 }
944 }
945 }
946 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200947
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200948 @Override
949 public void arpResponse(InetAddress ipAddress, byte[] macAddress) {
950 log.debug("Received ARP response: {} => {}", ipAddress.getHostAddress(),
951 MACAddress.valueOf(macAddress).toString());
952
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200953 /*
954 * We synchronize on this to prevent changes to the ptree while we're pushing
955 * flows to the switches. If the ptree changes, the ptree and switches
956 * could get out of sync.
957 */
958 synchronized (this) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200959 Path path = pathsWaitingOnArp.remove(ipAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200960
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200961 if (path != null) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200962 log.debug("Pushing path to {} at {} on {}", new Object[] {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200963 path.getDstIpAddress().getHostAddress(),
Jonathan Hart309889c2013-08-13 23:26:24 +1200964 MACAddress.valueOf(macAddress),
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200965 path.getDstInterface().getSwitchPort()});
966 //These paths should always be to BGP peers. Paths to non-peers are
967 //handled once the first prefix is ready to push
968 if (pushedPaths.containsKey(path.getDstInterface())) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200969 //A path already got pushed to this endpoint while we were waiting
970 //for ARP. We'll copy over the permanent attribute if it is set on this path.
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200971 if (path.isPermanent()) {
972 pushedPaths.get(path.getDstInterface()).setPermanent();
Jonathan Hart309889c2013-08-13 23:26:24 +1200973 }
974 }
975 else {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200976 setUpDataPath(path, MACAddress.valueOf(macAddress));
977 pushedPaths.put(path.getDstIpAddress(), path);
Jonathan Hart309889c2013-08-13 23:26:24 +1200978 }
979 }
980
Jonathan Hart309889c2013-08-13 23:26:24 +1200981 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
982
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200983 for (RibUpdate update : prefixesToPush) {
984 //These will always be adds
985
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200986 RibEntry rib = ptree.lookup(update.getPrefix());
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200987 if (rib != null && rib.equals(update.getRibEntry())) {
988 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200989 rib.getNextHop().getHostAddress());
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200990 //We only push prefix flows if the prefix is still in the ptree
991 //and the next hop is the same as our update. The prefix could
992 //have been removed while we were waiting for the ARP, or the
993 //next hop could have changed.
Jonathan Hart309889c2013-08-13 23:26:24 +1200994 _processRibAdd(update);
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200995 } else {
996 log.debug("Received ARP response, but {},{} is no longer in ptree",
997 update.getPrefix(), update.getRibEntry());
998 }
999 }
Jonathan Hart0ee0f022013-08-03 22:21:54 +12001000 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +12001001 }
1002
Jonathan Hartc82051c2013-08-24 15:12:20 +12001003 private void setupArpFlows() {
1004 OFMatch match = new OFMatch();
1005 match.setDataLayerType(Ethernet.TYPE_ARP);
1006 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1007
1008 OFFlowMod fm = new OFFlowMod();
1009 fm.setMatch(match);
1010
1011 OFActionOutput action = new OFActionOutput();
1012 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1013 action.setMaxLength((short)0xffff);
1014 List<OFAction> actions = new ArrayList<OFAction>(1);
1015 actions.add(action);
1016 fm.setActions(actions);
1017
1018 fm.setIdleTimeout((short)0)
1019 .setHardTimeout((short)0)
1020 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1021 .setCookie(0)
1022 .setCommand(OFFlowMod.OFPFC_ADD)
1023 .setPriority(ARP_PRIORITY)
1024 .setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1025
1026 for (String strdpid : switches){
1027 IOFSwitch sw = floodlightProvider.getSwitches().get(HexString.toLong(strdpid));
1028 if (sw == null) {
1029 log.debug("Couldn't find switch to push ARP flow");
1030 }
1031 else {
1032 try {
1033 sw.write(fm, null);
1034 } catch (IOException e) {
1035 log.warn("Failure writing ARP flow to switch", e);
1036 }
1037 }
1038 }
1039 }
1040
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001041 private void beginRouting(){
1042 log.debug("Topology is now ready, beginning routing function");
Jonathan Hartdefa44d2013-08-15 19:51:13 +12001043 topoRouteTopology = topoRouteService.prepareShortestPathTopo();
1044
Jonathan Hartc82051c2013-08-24 15:12:20 +12001045 setupArpFlows();
1046
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001047 setupBgpPaths();
Jonathan Hart98957bf2013-07-01 14:49:24 +12001048 setupFullMesh();
Jonathan Harte7694532013-09-12 12:34:46 +12001049
1050 //Suppress link discovery on external-facing router ports
1051 for (Interface intf : interfaces.values()) {
1052 linkDiscoveryService.AddToSuppressLLDPs(intf.getDpid(), intf.getPort());
1053 }
1054
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001055 bgpUpdatesExecutor.execute(new Runnable() {
1056 @Override
1057 public void run() {
1058 doUpdatesThread();
1059 }
1060 });
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001061 }
1062
1063 private void checkSwitchesConnected(){
1064 for (String dpid : switches){
1065 if (floodlightProvider.getSwitches().get(HexString.toLong(dpid)) == null){
1066 log.debug("Not all switches are here yet");
1067 return;
1068 }
1069 }
1070 switchesConnected = true;
1071 }
1072
Jonathan Hartc824ad02013-07-03 15:58:45 +12001073 //Actually we only need to go half way round to verify full mesh connectivity
1074 //(n^2)/2
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001075 private void checkTopologyReady(){
Jonathan Hartc824ad02013-07-03 15:58:45 +12001076 for (Interface dstInterface : interfaces.values()) {
1077 for (Interface srcInterface : interfaces.values()) {
1078 if (dstInterface == srcInterface) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001079 continue;
1080 }
1081
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001082 DataPath shortestPath = topoRouteService.getShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +12001083 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001084
1085 if (shortestPath == null){
1086 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +12001087 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001088 return;
1089 }
1090 }
1091 }
1092 topologyReady = true;
1093 }
1094
1095 private void checkStatus(){
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001096 if (!switchesConnected){
1097 checkSwitchesConnected();
1098 }
1099 boolean oldTopologyReadyStatus = topologyReady;
1100 if (switchesConnected && !topologyReady){
1101 checkTopologyReady();
1102 }
1103 if (!oldTopologyReadyStatus && topologyReady){
1104 beginRouting();
1105 }
1106 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001107
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001108 private void doUpdatesThread() {
1109 boolean interrupted = false;
1110 try {
1111 while (true) {
1112 try {
1113 RibUpdate update = ribUpdates.take();
1114 switch (update.getOperation()){
1115 case UPDATE:
Jonathan Hart2f740782013-08-04 00:49:21 +12001116 processRibAdd(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001117 break;
1118 case DELETE:
Jonathan Hart2f740782013-08-04 00:49:21 +12001119 processRibDelete(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001120 break;
1121 }
1122 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001123 log.debug("Interrupted while taking from updates queue", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001124 interrupted = true;
Jonathan Hart309889c2013-08-13 23:26:24 +12001125 } catch (Exception e) {
1126 log.debug("exception", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001127 }
1128 }
1129 } finally {
1130 if (interrupted) {
1131 Thread.currentThread().interrupt();
1132 }
1133 }
1134 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001135
1136 @Override
Jonathan Hart64c0b202013-08-20 15:45:07 +12001137 public void topologyChanged() {
1138 if (topologyReady) {
1139 return;
1140 }
1141
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001142 boolean refreshNeeded = false;
1143 for (LDUpdate ldu : topology.getLastLinkUpdates()){
1144 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1145 //We don't need to recalculate anything for just link updates
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001146 //They happen very frequently
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001147 refreshNeeded = true;
1148 }
Jonathan Hart98957bf2013-07-01 14:49:24 +12001149
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001150 log.debug("Topo change {}", ldu.getOperation());
Jonathan Hartc824ad02013-07-03 15:58:45 +12001151
Jonathan Hart98957bf2013-07-01 14:49:24 +12001152 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1153 synchronized (linkUpdates) {
1154 linkUpdates.add(ldu);
1155 }
1156 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001157 }
1158
Jonathan Hart64c0b202013-08-20 15:45:07 +12001159 if (refreshNeeded && !topologyReady){
Jonathan Hart98957bf2013-07-01 14:49:24 +12001160 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
pingping-lina2cbfad2013-03-07 08:39:21 +08001161 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001162 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001163
1164 @Override
1165 public void addedSwitch(IOFSwitch sw) {
1166 if (!topologyReady) {
1167 sw.clearAllFlowMods();
1168 }
1169 }
1170
1171 @Override
1172 public void removedSwitch(IOFSwitch sw) {
1173 // TODO Auto-generated method stub
1174
1175 }
1176
1177 @Override
1178 public void switchPortChanged(Long switchId) {
1179 // TODO Auto-generated method stub
1180
1181 }
1182
1183 @Override
1184 public String getName() {
1185 // TODO Auto-generated method stub
1186 return null;
1187 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001188}