blob: aed82b3b7edbfc815b5e3d4ada8b533cbeeadf1c [file] [log] [blame]
Jonathan Hart382623d2014-04-03 09:48:11 -07001package net.onrc.onos.apps.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 Harte7e1c6e2013-06-04 20:50:23 -07009import java.util.List;
Jonathan Hart61ba9372013-05-19 20:10:29 -070010import java.util.Map;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120011import java.util.Set;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120012import java.util.concurrent.BlockingQueue;
13import java.util.concurrent.ExecutorService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120014import java.util.concurrent.Executors;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120015import java.util.concurrent.LinkedBlockingQueue;
Jonathan Hart98957bf2013-07-01 14:49:24 +120016import java.util.concurrent.ScheduledExecutorService;
17import java.util.concurrent.TimeUnit;
pingping-lina2cbfad2013-03-07 08:39:21 +080018
Jonathan Hart61ba9372013-05-19 20:10:29 -070019import net.floodlightcontroller.core.IFloodlightProviderService;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070020import net.floodlightcontroller.core.IOFSwitch;
Jonathan Hart64c0b202013-08-20 15:45:07 +120021import net.floodlightcontroller.core.IOFSwitchListener;
pingping-lina2cbfad2013-03-07 08:39:21 +080022import net.floodlightcontroller.core.module.FloodlightModuleContext;
23import net.floodlightcontroller.core.module.FloodlightModuleException;
24import net.floodlightcontroller.core.module.IFloodlightModule;
25import net.floodlightcontroller.core.module.IFloodlightService;
Jonathan Hart98957bf2013-07-01 14:49:24 +120026import net.floodlightcontroller.core.util.SingletonTask;
pingping-lina2cbfad2013-03-07 08:39:21 +080027import net.floodlightcontroller.restserver.IRestApiService;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120028import net.floodlightcontroller.util.MACAddress;
Jonathan Hart382623d2014-04-03 09:48:11 -070029import net.onrc.onos.apps.bgproute.RibUpdate.Operation;
Jonathan Hart0961fe82014-04-03 09:56:25 -070030import net.onrc.onos.apps.proxyarp.IArpRequester;
31import net.onrc.onos.apps.proxyarp.IProxyArpService;
Jonathan Hart23701d12014-04-03 10:45:48 -070032import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryService;
33import net.onrc.onos.core.linkdiscovery.ILinkDiscovery.LDUpdate;
Jonathan Hart51f6f5b2014-04-03 10:32:10 -070034import net.onrc.onos.core.main.config.IConfigInfoService;
Jonathan Hart23701d12014-04-03 10:45:48 -070035import net.onrc.onos.core.util.CallerId;
36import net.onrc.onos.core.util.DataPath;
37import net.onrc.onos.core.util.Dpid;
38import net.onrc.onos.core.util.FlowEntryAction;
39import net.onrc.onos.core.util.FlowEntryActions;
40import net.onrc.onos.core.util.FlowEntryMatch;
41import net.onrc.onos.core.util.FlowId;
42import net.onrc.onos.core.util.FlowPath;
43import net.onrc.onos.core.util.FlowPathFlags;
44import net.onrc.onos.core.util.FlowPathType;
45import net.onrc.onos.core.util.FlowPathUserState;
46import net.onrc.onos.core.util.IPv4Net;
47import net.onrc.onos.core.util.Port;
48import net.onrc.onos.core.util.SwitchPort;
Jonathan Hart96892d12014-03-26 20:21:29 -070049import net.onrc.onos.packet.Ethernet;
50import net.onrc.onos.packet.IPv4;
pingping-line2a09ca2013-03-23 09:33:58 +080051import net.sf.json.JSONArray;
52import net.sf.json.JSONObject;
53import net.sf.json.JSONSerializer;
pingping-lina2cbfad2013-03-07 08:39:21 +080054
Jonathan Hartd1f23252013-06-13 15:17:05 +120055import org.codehaus.jackson.JsonParseException;
56import org.codehaus.jackson.map.JsonMappingException;
57import org.codehaus.jackson.map.ObjectMapper;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070058import org.openflow.protocol.OFFlowMod;
59import org.openflow.protocol.OFMatch;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070060import org.openflow.protocol.OFPacketOut;
Jonathan Hart9575cb62013-07-05 13:43:49 +120061import org.openflow.protocol.OFPort;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070062import org.openflow.protocol.action.OFAction;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070063import org.openflow.protocol.action.OFActionOutput;
Jonathan Hart1236a9b2013-06-18 22:10:05 +120064import org.openflow.util.HexString;
pingping-lina2cbfad2013-03-07 08:39:21 +080065import org.slf4j.Logger;
66import org.slf4j.LoggerFactory;
67
Jonathan Hart4dfc3652013-08-02 20:22:36 +120068import com.google.common.collect.HashMultimap;
Jonathan Hart0ee0f022013-08-03 22:21:54 +120069import com.google.common.collect.Multimap;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120070import com.google.common.collect.Multimaps;
71import com.google.common.collect.SetMultimap;
Jonathan Hart309889c2013-08-13 23:26:24 +120072import com.google.common.net.InetAddresses;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120073import com.google.common.util.concurrent.ThreadFactoryBuilder;
74
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070075public class BgpRoute implements IFloodlightModule, IBgpRouteService,
Jonathan Hart02a59e42014-03-26 18:50:23 -070076 IArpRequester,
Jonathan Hart7804bea2014-01-07 10:50:52 -080077 IOFSwitchListener, IConfigInfoService {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070078
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -070079 private final static Logger log = LoggerFactory.getLogger(BgpRoute.class);
pingping-lina2cbfad2013-03-07 08:39:21 +080080
Jonathan Hartf247ee72013-10-18 18:57:28 -070081 private IFloodlightProviderService floodlightProvider;
Jonathan Hartf247ee72013-10-18 18:57:28 -070082 private ILinkDiscoveryService linkDiscoveryService;
83 private IRestApiService restApi;
pingping-linba5c52f2014-02-11 16:52:01 -080084 private IProxyArpService proxyArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070085
Jonathan Hartf247ee72013-10-18 18:57:28 -070086 private IPatriciaTrie<RibEntry> ptree;
87 private IPatriciaTrie<Interface> interfacePtrie;
88 private BlockingQueue<RibUpdate> ribUpdates;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070089
Jonathan Hartf247ee72013-10-18 18:57:28 -070090 private String bgpdRestIp;
91 private String routerId;
92 private String configFilename = "config.json";
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070093
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070094 //We need to identify our flows somehow. But like it says in LearningSwitch.java,
95 //the controller/OS should hand out cookie IDs to prevent conflicts.
Jonathan Hartf247ee72013-10-18 18:57:28 -070096 private final long APP_COOKIE = 0xa0000000000000L;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070097 //Cookie for flows that do L2 forwarding within SDN domain to egress routers
Jonathan Hartf247ee72013-10-18 18:57:28 -070098 private final long L2_FWD_COOKIE = APP_COOKIE + 1;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070099 //Cookie for flows in ingress switches that rewrite the MAC address
Jonathan Hartf247ee72013-10-18 18:57:28 -0700100 private final long MAC_RW_COOKIE = APP_COOKIE + 2;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200101 //Cookie for flows that setup BGP paths
Jonathan Hartf247ee72013-10-18 18:57:28 -0700102 private final long BGP_COOKIE = APP_COOKIE + 3;
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200103 //Forwarding uses priority 0, and the mac rewrite entries in ingress switches
104 //need to be higher priority than this otherwise the rewrite may not get done
Jonathan Hartf247ee72013-10-18 18:57:28 -0700105 private final short SDNIP_PRIORITY = 10;
106 private final short ARP_PRIORITY = 20;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700107
Jonathan Hartf247ee72013-10-18 18:57:28 -0700108 private final short BGP_PORT = 179;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700109
Jonathan Hartf247ee72013-10-18 18:57:28 -0700110 private final int TOPO_DETECTION_WAIT = 2; //seconds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700111
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200112 //Configuration stuff
Jonathan Hartf247ee72013-10-18 18:57:28 -0700113 private List<String> switches;
114 private Map<String, Interface> interfaces;
115 private Map<InetAddress, BgpPeer> bgpPeers;
116 private SwitchPort bgpdAttachmentPoint;
117 private MACAddress bgpdMacAddress;
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700118 private short vlan;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700119
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200120 //True when all switches have connected
Jonathan Hartf247ee72013-10-18 18:57:28 -0700121 private volatile boolean switchesConnected = false;
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200122 //True when we have a full mesh of shortest paths between gateways
Jonathan Hartf247ee72013-10-18 18:57:28 -0700123 private volatile boolean topologyReady = false;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200124
Jonathan Hartf247ee72013-10-18 18:57:28 -0700125 private ArrayList<LDUpdate> linkUpdates;
126 private SingletonTask topologyChangeDetectorTask;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700127
Jonathan Hartf247ee72013-10-18 18:57:28 -0700128 private SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700129
Jonathan Hartf247ee72013-10-18 18:57:28 -0700130 private Map<InetAddress, Path> pathsWaitingOnArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700131
Jonathan Hartf247ee72013-10-18 18:57:28 -0700132 private ExecutorService bgpUpdatesExecutor;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700133
Jonathan Hartf247ee72013-10-18 18:57:28 -0700134 private Map<InetAddress, Path> pushedPaths;
135 private Map<Prefix, Path> prefixToPath;
pingping-linba5c52f2014-02-11 16:52:01 -0800136// private Multimap<Prefix, PushedFlowMod> pushedFlows;
137 private Multimap<Prefix, FlowId> pushedFlowIds;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700138
Jonathan Hart1912afc2013-10-11 12:02:44 +1300139 private FlowCache flowCache;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700140
Pavlin Radoslavov1237e392014-03-20 16:24:06 -0700141 // TODO: Fix for the new Topology Network Graph
142 // private volatile Topology topology = null;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700143
Jonathan Hartf247ee72013-10-18 18:57:28 -0700144 private class TopologyChangeDetector implements Runnable {
Jonathan Hart98957bf2013-07-01 14:49:24 +1200145 @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
Pavlin Radoslavov5fe71882014-03-21 16:27:21 -0700150 // TODO: Fix the code below after topoLinkService was removed
151 /*
Jonathan Hart98957bf2013-07-01 14:49:24 +1200152 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700153
Jonathan Hart98957bf2013-07-01 14:49:24 +1200154 List<Link> activeLinks = topoLinkService.getActiveLinks();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700155
Jonathan Hart98957bf2013-07-01 14:49:24 +1200156 Iterator<LDUpdate> it = linkUpdates.iterator();
157 while (it.hasNext()){
158 LDUpdate ldu = it.next();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700159 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
Jonathan Hart98957bf2013-07-01 14:49:24 +1200160 ldu.getDst(), ldu.getDstPort());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700161
Jonathan Hart98957bf2013-07-01 14:49:24 +1200162 if (activeLinks.contains(l)){
Jonathan Hart98957bf2013-07-01 14:49:24 +1200163 it.remove();
164 }
165 }
Pavlin Radoslavov5fe71882014-03-21 16:27:21 -0700166 */
Jonathan Hart98957bf2013-07-01 14:49:24 +1200167 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700168
Jonathan Hart64c0b202013-08-20 15:45:07 +1200169 if (!topologyReady) {
170 if (linkUpdates.isEmpty()){
171 //All updates have been seen in network map.
172 //We can check if topology is ready
173 log.debug("No known changes outstanding. Checking topology now");
174 checkStatus();
175 }
176 else {
177 //We know of some link updates that haven't propagated to the database yet
178 log.debug("Some changes not found in network map - {} links missing", linkUpdates.size());
179 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
180 }
Jonathan Hart98957bf2013-07-01 14:49:24 +1200181 }
182 }
183 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700184
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700185 private void readConfiguration(String configFilename){
186 File gatewaysFile = new File(configFilename);
Jonathan Hartd1f23252013-06-13 15:17:05 +1200187 ObjectMapper mapper = new ObjectMapper();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700188
Jonathan Hartd1f23252013-06-13 15:17:05 +1200189 try {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200190 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700191
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200192 switches = config.getSwitches();
Jonathan Hart9575cb62013-07-05 13:43:49 +1200193 interfaces = new HashMap<String, Interface>();
194 for (Interface intf : config.getInterfaces()){
195 interfaces.put(intf.getName(), intf);
196 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200197 bgpPeers = new HashMap<InetAddress, BgpPeer>();
198 for (BgpPeer peer : config.getPeers()){
199 bgpPeers.put(peer.getIpAddress(), peer);
200 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700201
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200202 bgpdAttachmentPoint = new SwitchPort(
203 new Dpid(config.getBgpdAttachmentDpid()),
204 new Port(config.getBgpdAttachmentPort()));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700205
Jonathan Hart2f790d22013-08-15 14:01:24 +1200206 bgpdMacAddress = config.getBgpdMacAddress();
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700207 vlan = config.getVlan();
Jonathan Hartd1f23252013-06-13 15:17:05 +1200208 } catch (JsonParseException e) {
209 log.error("Error in JSON file", e);
210 System.exit(1);
211 } catch (JsonMappingException e) {
212 log.error("Error in JSON file", e);
213 System.exit(1);
214 } catch (IOException e) {
215 log.error("Error reading JSON file", e);
216 System.exit(1);
217 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700218
Jonathan Hartabf10222013-08-13 10:19:34 +1200219 //Populate the interface Patricia Trie
220 for (Interface intf : interfaces.values()) {
221 Prefix prefix = new Prefix(intf.getIpAddress().getAddress(), intf.getPrefixLength());
222 interfacePtrie.put(prefix, intf);
223 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700224 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700225
pingping-lina2cbfad2013-03-07 08:39:21 +0800226 @Override
227 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700228 Collection<Class<? extends IFloodlightService>> l
Jonathan Hart61ba9372013-05-19 20:10:29 -0700229 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800230 l.add(IBgpRouteService.class);
Jonathan Harta8887642013-10-28 13:46:54 -0700231 l.add(IConfigInfoService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800232 return l;
233 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700234
pingping-lina2cbfad2013-03-07 08:39:21 +0800235 @Override
236 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700237 Map<Class<? extends IFloodlightService>, IFloodlightService> m
Jonathan Hart61ba9372013-05-19 20:10:29 -0700238 = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
pingping-line2a09ca2013-03-23 09:33:58 +0800239 m.put(IBgpRouteService.class, this);
Jonathan Harta8887642013-10-28 13:46:54 -0700240 m.put(IConfigInfoService.class, this);
pingping-lina2cbfad2013-03-07 08:39:21 +0800241 return m;
242 }
243
pingping-lina2cbfad2013-03-07 08:39:21 +0800244 @Override
245 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700246 Collection<Class<? extends IFloodlightService>> l
Jonathan Hart61ba9372013-05-19 20:10:29 -0700247 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800248 l.add(IFloodlightProviderService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700249 l.add(IRestApiService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800250 return l;
251 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700252
pingping-lina2cbfad2013-03-07 08:39:21 +0800253 @Override
254 public void init(FloodlightModuleContext context)
255 throws FloodlightModuleException {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700256
Jonathan Hart29b972d2013-08-12 23:43:51 +1200257 ptree = new PatriciaTrie<RibEntry>(32);
Jonathan Hartabf10222013-08-13 10:19:34 +1200258 interfacePtrie = new PatriciaTrie<Interface>(32);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700259
pingping-linba5c52f2014-02-11 16:52:01 -0800260 ribUpdates = new LinkedBlockingQueue<RibUpdate>();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700261
pingping-lina2cbfad2013-03-07 08:39:21 +0800262 // Register floodlight provider and REST handler.
263 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Jonathan Harte7694532013-09-12 12:34:46 +1200264 linkDiscoveryService = context.getServiceImpl(ILinkDiscoveryService.class);
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200265 restApi = context.getServiceImpl(IRestApiService.class);
pingping-linba5c52f2014-02-11 16:52:01 -0800266 proxyArp = context.getServiceImpl(IProxyArpService.class);
267
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
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200272 pathsWaitingOnArp = new HashMap<InetAddress, Path>();
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200273 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
274 HashMultimap.<InetAddress, RibUpdate>create());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700275
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200276 pushedPaths = new HashMap<InetAddress, Path>();
277 prefixToPath = new HashMap<Prefix, Path>();
pingping-linba5c52f2014-02-11 16:52:01 -0800278// pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
279 pushedFlowIds = HashMultimap.<Prefix, FlowId>create();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700280
Jonathan Hart1912afc2013-10-11 12:02:44 +1300281 flowCache = new FlowCache(floodlightProvider);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700282
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200283 bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
284 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700285
Jonathan Hart61ba9372013-05-19 20:10:29 -0700286 //Read in config values
287 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
288 if (bgpdRestIp == null){
289 log.error("BgpdRestIp property not found in config file");
290 System.exit(1);
291 }
292 else {
293 log.info("BgpdRestIp set to {}", bgpdRestIp);
294 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700295
Jonathan Hart61ba9372013-05-19 20:10:29 -0700296 routerId = context.getConfigParams(this).get("RouterId");
297 if (routerId == null){
298 log.error("RouterId property not found in config file");
299 System.exit(1);
300 }
301 else {
302 log.info("RouterId set to {}", routerId);
303 }
pingping-linba5c52f2014-02-11 16:52:01 -0800304
Jonathan Hart9575cb62013-07-05 13:43:49 +1200305 String configFilenameParameter = context.getConfigParams(this).get("configfile");
306 if (configFilenameParameter != null){
307 configFilename = configFilenameParameter;
308 }
309 log.debug("Config file set to {}", configFilename);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700310
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700311 readConfiguration(configFilename);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200312 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700313
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200314 @Override
315 public void startUp(FloodlightModuleContext context) {
316 restApi.addRestletRoutable(new BgpRouteWebRoutable());
Jonathan Hart64c0b202013-08-20 15:45:07 +1200317 floodlightProvider.addOFSwitchListener(this);
pingping-linba5c52f2014-02-11 16:52:01 -0800318
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200319 //Retrieve the RIB from BGPd during startup
320 retrieveRib();
pingping-lina2cbfad2013-03-07 08:39:21 +0800321 }
322
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700323 @Override
Jonathan Hart29b972d2013-08-12 23:43:51 +1200324 public IPatriciaTrie<RibEntry> getPtree() {
pingping-lina2cbfad2013-03-07 08:39:21 +0800325 return ptree;
326 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700327
328 @Override
Jonathan Hart61ba9372013-05-19 20:10:29 -0700329 public void clearPtree() {
Jonathan Hart29b972d2013-08-12 23:43:51 +1200330 ptree = new PatriciaTrie<RibEntry>(32);
pingping-line2a09ca2013-03-23 09:33:58 +0800331 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700332
333 @Override
pingping-line2a09ca2013-03-23 09:33:58 +0800334 public String getBGPdRestIp() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700335 return bgpdRestIp;
pingping-line2a09ca2013-03-23 09:33:58 +0800336 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700337
338 @Override
pingping-line2a09ca2013-03-23 09:33:58 +0800339 public String getRouterId() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700340 return routerId;
pingping-line2a09ca2013-03-23 09:33:58 +0800341 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700342
Jonathan Hart61ba9372013-05-19 20:10:29 -0700343 private void retrieveRib(){
344 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
345 String response = RestClient.get(url);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700346
Jonathan Hart61ba9372013-05-19 20:10:29 -0700347 if (response.equals("")){
348 return;
349 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700350
Jonathan Hart61ba9372013-05-19 20:10:29 -0700351 response = response.replaceAll("\"", "'");
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700352 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
Jonathan Hart61ba9372013-05-19 20:10:29 -0700353 JSONArray rib_json_array = jsonObj.getJSONArray("rib");
354 String router_id = jsonObj.getString("router-id");
355
356 int size = rib_json_array.size();
357
358 log.info("Retrived RIB of {} entries from BGPd", size);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700359
Jonathan Hart61ba9372013-05-19 20:10:29 -0700360 for (int j = 0; j < size; j++) {
361 JSONObject second_json_object = rib_json_array.getJSONObject(j);
362 String prefix = second_json_object.getString("prefix");
363 String nexthop = second_json_object.getString("nexthop");
364
365 //insert each rib entry into the local rib;
366 String[] substring = prefix.split("/");
367 String prefix1 = substring[0];
368 String mask1 = substring[1];
369
370 Prefix p;
371 try {
372 p = new Prefix(prefix1, Integer.valueOf(mask1));
373 } catch (NumberFormatException e) {
374 log.warn("Wrong mask format in RIB JSON: {}", mask1);
375 continue;
Jonathan Hart32e18222013-08-07 22:05:42 +1200376 } catch (IllegalArgumentException e1) {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700377 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
378 continue;
379 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700380
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200381 RibEntry rib = new RibEntry(router_id, nexthop);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700382
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200383 try {
384 ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
385 } catch (InterruptedException e) {
386 log.debug("Interrupted while pushing onto update queue");
387 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700388 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700389 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700390
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200391 @Override
392 public void newRibUpdate(RibUpdate update) {
Jonathan Hart9ea31212013-08-12 21:40:34 +1200393 try {
394 ribUpdates.put(update);
395 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200396 log.debug("Interrupted while putting on ribUpdates queue", e);
397 Thread.currentThread().interrupt();
Jonathan Hart9ea31212013-08-12 21:40:34 +1200398 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200399 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700400
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200401 public synchronized void processRibAdd(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200402 Prefix prefix = update.getPrefix();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700403
Jonathan Hart9ea31212013-08-12 21:40:34 +1200404 log.debug("Processing prefix add {}", prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700405
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200406 RibEntry rib = ptree.put(prefix, update.getRibEntry());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700407
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200408 if (rib != null && !rib.equals(update.getRibEntry())) {
Jonathan Hart2f740782013-08-04 00:49:21 +1200409 //There was an existing nexthop for this prefix. This update supersedes that,
410 //so we need to remove the old flows for this prefix from the switches
Jonathan Hart309889c2013-08-13 23:26:24 +1200411 _processDeletePrefix(prefix, rib);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200412 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700413
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200414 if (update.getRibEntry().getNextHop().equals(
415 InetAddresses.forString("0.0.0.0"))) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200416 //Route originated by SDN domain
417 //We don't handle these at the moment
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700418 log.debug("Own route {} to {}", prefix,
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200419 update.getRibEntry().getNextHop().getHostAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200420 return;
421 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700422
Jonathan Hart309889c2013-08-13 23:26:24 +1200423 _processRibAdd(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200424 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700425
Jonathan Hart309889c2013-08-13 23:26:24 +1200426 private void _processRibAdd(RibUpdate update) {
427 Prefix prefix = update.getPrefix();
428 RibEntry rib = update.getRibEntry();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700429
Jonathan Hart309889c2013-08-13 23:26:24 +1200430 InetAddress dstIpAddress = rib.getNextHop();
Pavlin Radoslavov5fe71882014-03-21 16:27:21 -0700431 MACAddress nextHopMacAddress = null;
pingping-linba5c52f2014-02-11 16:52:01 -0800432
433 // See if we know the MAC address of the next hop
434 // TODO if we do not treat the next hop as a device in the future, we need to update this
Pavlin Radoslavov5fe71882014-03-21 16:27:21 -0700435 // TODO: Fix the code below after deviceStorage was removed
436 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800437 IDeviceObject nextHopDevice =
438 deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(dstIpAddress));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700439
pingping-linba5c52f2014-02-11 16:52:01 -0800440 if (nextHopDevice == null){
441 log.debug("NextHopDevice for IP: {} is null", dstIpAddress);
442 prefixesWaitingOnArp.put(dstIpAddress,
443 new RibUpdate(Operation.UPDATE, prefix, rib));
444 proxyArp.sendArpRequest(dstIpAddress, this, true);
445 return;
446
447 }
448 nextHopMacAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
Pavlin Radoslavov5fe71882014-03-21 16:27:21 -0700449 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700450
pingping-linba5c52f2014-02-11 16:52:01 -0800451 // Find the attachment point (egress interface) of the next hop
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200452 Interface egressInterface = null;
Jonathan Hart309889c2013-08-13 23:26:24 +1200453 if (bgpPeers.containsKey(dstIpAddress)) {
454 //Route to a peer
455 log.debug("Route to peer {}", dstIpAddress);
456 BgpPeer peer = bgpPeers.get(dstIpAddress);
457 egressInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart309889c2013-08-13 23:26:24 +1200458 }
459 else {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200460 //Route to non-peer
Jonathan Hart309889c2013-08-13 23:26:24 +1200461 log.debug("Route to non-peer {}", dstIpAddress);
462 egressInterface = interfacePtrie.match(
463 new Prefix(dstIpAddress.getAddress(), 32));
464 if (egressInterface == null) {
465 log.warn("No outgoing interface found for {}", dstIpAddress.getHostAddress());
466 return;
467 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200468 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700469
Jonathan Hart309889c2013-08-13 23:26:24 +1200470 if (nextHopMacAddress == null) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700471 prefixesWaitingOnArp.put(dstIpAddress,
Jonathan Hart309889c2013-08-13 23:26:24 +1200472 new RibUpdate(Operation.UPDATE, prefix, rib));
473 proxyArp.sendArpRequest(dstIpAddress, this, true);
474 return;
475 }
476 else {
477 if (!bgpPeers.containsKey(dstIpAddress)) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200478 //If the prefix is for a non-peer we need to ensure there's a path,
479 //and push one if there isn't.
480 Path path = pushedPaths.get(dstIpAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200481 if (path == null) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200482 path = new Path(egressInterface, dstIpAddress);
Jonathan Hartabad6a52013-09-30 18:17:21 +1300483 calculateAndPushPath(path, nextHopMacAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200484 pushedPaths.put(dstIpAddress, path);
485 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700486
Jonathan Hart309889c2013-08-13 23:26:24 +1200487 path.incrementUsers();
488 prefixToPath.put(prefix, path);
489 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700490
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200491 //For all prefixes we need to add the first-hop mac-rewriting flows
Jonathan Hart309889c2013-08-13 23:26:24 +1200492 addPrefixFlows(prefix, egressInterface, nextHopMacAddress);
493 }
494 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700495
pingping-linba5c52f2014-02-11 16:52:01 -0800496 /**
497 * Add a flow to match dst-IP prefix and rewrite MAC for one IP prefix
498 * to all other border switches
499 */
500 private void addPrefixFlows(Prefix prefix, Interface egressInterface,
501 MACAddress nextHopMacAddress) {
Jonathan Harte4c98692013-10-18 17:40:03 -0700502 log.debug("Adding flows for prefix {}, next hop mac {}",
Jonathan Hartabad6a52013-09-30 18:17:21 +1300503 prefix, nextHopMacAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700504
pingping-linba5c52f2014-02-11 16:52:01 -0800505 FlowPath flowPath = new FlowPath();
506 flowPath.setInstallerId(new CallerId("SDNIP"));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700507
pingping-linba5c52f2014-02-11 16:52:01 -0800508 // Set flowPath FlowPathType and FlowPathUserState
509 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
510 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
511
512 // Insert dst-ip prefix based forwarding and MAC rewrite flow entry
513 // only to the first-host switches
514 FlowPathFlags flowPathFlags = new FlowPathFlags();
515 flowPathFlags.setFlags(FlowPathFlags.KEEP_ONLY_FIRST_HOP_ENTRY);
516 flowPath.setFlowPathFlags(flowPathFlags);
517
518 // Create the DataPath object: dstSwitchPort
519 SwitchPort dstPort = new SwitchPort();
520 dstPort.setDpid(new Dpid(egressInterface.getDpid()));
521 dstPort.setPort(new Port(egressInterface.getPort()));
522
523 // We only need one flow mod per switch, so pick one interface on each switch
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200524 Map<Long, Interface> srcInterfaces = new HashMap<Long, Interface>();
525 for (Interface intf : interfaces.values()) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700526 if (!srcInterfaces.containsKey(intf.getDpid())
Jonathan Hart45107222013-10-22 17:35:04 -0700527 && !intf.equals(egressInterface)) {
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200528 srcInterfaces.put(intf.getDpid(), intf);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200529 }
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200530 }
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200531 for (Interface srcInterface : srcInterfaces.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800532
533 if (egressInterface.equals(srcInterface)){
534 continue;
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200535 }
pingping-linba5c52f2014-02-11 16:52:01 -0800536
537 // Create flowPath FlowId
pingping-linba5c52f2014-02-11 16:52:01 -0800538 flowPath.setFlowId(new FlowId());
539
540 // Create DataPath object: srcSwitchPort
541 SwitchPort srcPort = new SwitchPort();
542 srcPort.setDpid(new Dpid(srcInterface.getDpid()));
543 srcPort.setPort(new Port(srcInterface.getPort()));
544
545 DataPath dataPath = new DataPath();
546 dataPath.setSrcPort(srcPort);
547 dataPath.setDstPort(dstPort);
548 flowPath.setDataPath(dataPath);
549
550 // Create flow path matching condition(s): IPv4 Prefix
551 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
552 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPv4);
553 IPv4Net dstIPv4Net= new IPv4Net(prefix.toString());
554 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
555 flowPath.setFlowEntryMatch(flowEntryMatch);
Jonathan Hart1912afc2013-10-11 12:02:44 +1300556
557 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800558 * Create the Flow Entry Action(s): dst-MAC rewrite action
Jonathan Hart1912afc2013-10-11 12:02:44 +1300559 */
pingping-linba5c52f2014-02-11 16:52:01 -0800560 FlowEntryActions flowEntryActions = new FlowEntryActions();
561 FlowEntryAction flowEntryAction1 = new FlowEntryAction();
562 flowEntryAction1.setActionSetEthernetDstAddr(nextHopMacAddress);
563 // flowEntryAction1.actionSetEthernetDstAddr(nextHopMacAddress);
564 flowEntryActions.addAction(flowEntryAction1);
565 flowPath.setFlowEntryActions(flowEntryActions);
566
567 // Flow Path installation, only to first hop switches
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700568 // TODO: Add the flow by using the new Path Intent framework
569 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800570 if (flowManagerService.addFlow(flowPath) == null) {
571 log.error("Failed to install flow path to the first hop for " +
572 "prefix: {}, nextHopMacAddress: {}", prefix.getAddress(),
573 nextHopMacAddress);
574 }
575 else {
576 log.debug("Successfully installed flow path to the first hop " +
577 "for prefix: {}, nextHopMacAddress: {}", prefix.getAddress(),
578 nextHopMacAddress);
579
580 pushedFlowIds.put(prefix, flowPath.flowId());
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200581 }
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700582 */
Jonathan Hart309889c2013-08-13 23:26:24 +1200583 }
584 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700585
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200586 public synchronized void processRibDelete(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200587 Prefix prefix = update.getPrefix();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700588
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200589 if (ptree.remove(prefix, update.getRibEntry())) {
590 /*
591 * Only delete flows if an entry was actually removed from the trie.
592 * If no entry was removed, the <prefix, nexthop> wasn't there so
593 * it's probably already been removed and we don't need to do anything
594 */
Jonathan Hart309889c2013-08-13 23:26:24 +1200595 _processDeletePrefix(prefix, update.getRibEntry());
Jonathan Hart309889c2013-08-13 23:26:24 +1200596 }
597 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700598
Jonathan Hart309889c2013-08-13 23:26:24 +1200599 private void _processDeletePrefix(Prefix prefix, RibEntry ribEntry) {
600 deletePrefixFlows(prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700601
Jonathan Hart309889c2013-08-13 23:26:24 +1200602 log.debug("Deleting {} to {}", prefix, ribEntry.getNextHop());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700603
Jonathan Hart309889c2013-08-13 23:26:24 +1200604 if (!bgpPeers.containsKey(ribEntry.getNextHop())) {
605 log.debug("Getting path for route with non-peer nexthop");
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200606 Path path = prefixToPath.remove(prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700607
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200608 if (path != null) {
609 //path could be null if we added to the Ptree but didn't push
610 //flows yet because we were waiting to resolve ARP
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700611
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200612 path.decrementUsers();
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200613 if (path.getUsers() <= 0 && !path.isPermanent()) {
614 deletePath(path);
615 pushedPaths.remove(path.getDstIpAddress());
616 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200617 }
618 }
619 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700620
pingping-linba5c52f2014-02-11 16:52:01 -0800621 // TODO have not tested this module
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200622 private void deletePrefixFlows(Prefix prefix) {
623 log.debug("Deleting flows for prefix {}", prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700624
pingping-linba5c52f2014-02-11 16:52:01 -0800625 Collection<FlowId> flowIds = pushedFlowIds.removeAll(prefix);
626 for (FlowId flowId : flowIds) {
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700627 // TODO: Delete the flow by using the new Path Intent framework
628 /*
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200629 if (log.isTraceEnabled()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800630 //Trace the flow status by flowPath in the switch before deleting it
631 log.trace("Pushing a DELETE flow mod to flowPath : {}",
632 flowManagerService.getFlow(flowId).toString());
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200633 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700634
pingping-linba5c52f2014-02-11 16:52:01 -0800635 if( flowManagerService.deleteFlow(flowId))
636 {
637 log.debug("Successfully deleted FlowId: {}",flowId);
638 }
639 else
640 {
641 log.debug("Failed to delete FlowId: {}",flowId);
642 }
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700643 */
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200644 }
645 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700646
pingping-linba5c52f2014-02-11 16:52:01 -0800647 // TODO need to record the path and then delete here
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200648 private void deletePath(Path path) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700649 log.debug("Deleting flows for path to {}",
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200650 path.getDstIpAddress().getHostAddress());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700651
pingping-linba5c52f2014-02-11 16:52:01 -0800652 // TODO need update
653 /*for (PushedFlowMod pfm : path.getFlowMods()) {
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200654 if (log.isTraceEnabled()) {
655 log.trace("Pushing a DELETE flow mod to {}, dst MAC {}",
656 new Object[] {HexString.toHexString(pfm.getDpid()),
657 HexString.toHexString(pfm.getFlowMod().getMatch().getDataLayerDestination())
658 });
659 }
pingping-linba5c52f2014-02-11 16:52:01 -0800660
Jonathan Hart309889c2013-08-13 23:26:24 +1200661 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
pingping-linba5c52f2014-02-11 16:52:01 -0800662 }*/
Jonathan Hart309889c2013-08-13 23:26:24 +1200663 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700664
665
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200666 //TODO test next-hop changes
Jonathan Hart2f740782013-08-04 00:49:21 +1200667 //TODO check delete/add synchronization
pingping-linba5c52f2014-02-11 16:52:01 -0800668
669 /**
670 * On startup, we need to calculate a full mesh of paths between all gateway
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700671 * switches
672 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200673 private void setupFullMesh(){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700674 //For each border router, calculate and install a path from every other
675 //border switch to said border router. However, don't install the entry
676 //in to the first hop switch, as we need to install an entry to rewrite
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700677 //for each prefix received. This will be done later when prefixes have
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700678 //actually been received.
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700679
Jonathan Hartc824ad02013-07-03 15:58:45 +1200680 for (BgpPeer peer : bgpPeers.values()) {
681 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700682
Jonathan Hart309889c2013-08-13 23:26:24 +1200683 //We know there's not already a Path here pushed, because this is
684 //called before all other routing
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200685 Path path = new Path(peerInterface, peer.getIpAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200686 path.setPermanent();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700687
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200688 //See if we know the MAC address of the peer. If not we can't
689 //do anything until we learn it
Pavlin Radoslavov5fe71882014-03-21 16:27:21 -0700690 // TODO: Fix the code below after deviceStorage was removed
691 MACAddress macAddress = null;
692 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800693 IDeviceObject nextHopDevice =
694 deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(peer.getIpAddress()));
695
696 if(nextHopDevice == null){
697 log.debug("There is no DeviceObject for {}", peer.getIpAddress().getHostAddress());
698 //Put in the pending paths list first
699 pathsWaitingOnArp.put(peer.getIpAddress(), path);
700 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
701 continue;
702 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700703
pingping-linba5c52f2014-02-11 16:52:01 -0800704 macAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
Pavlin Radoslavov5fe71882014-03-21 16:27:21 -0700705 */
pingping-linba5c52f2014-02-11 16:52:01 -0800706
Jonathan Hartabad6a52013-09-30 18:17:21 +1300707 if (macAddress == null) {
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200708 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
709 //Put in the pending paths list first
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200710 pathsWaitingOnArp.put(peer.getIpAddress(), path);
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200711 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
712 continue;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700713 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700714
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200715 //If we know the MAC, lets go ahead and push the paths to this peer
Jonathan Hartabad6a52013-09-30 18:17:21 +1300716 calculateAndPushPath(path, macAddress);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700717 }
718 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700719
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200720 private void calculateAndPushPath(Path path, MACAddress dstMacAddress) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200721 Interface dstInterface = path.getDstInterface();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700722
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200723 log.debug("Setting up path to {}, {}", path.getDstIpAddress().getHostAddress(),
724 dstMacAddress);
pingping-linba5c52f2014-02-11 16:52:01 -0800725
726 FlowPath flowPath = new FlowPath();
727
728 flowPath.setInstallerId(new CallerId("SDNIP"));
729
730 // Set flowPath FlowPathType and FlowPathUserState
731 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
732 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
733
734 // Insert the dest-mac based forwarding flow entry to the non-first-hop switches
735 FlowPathFlags flowPathFlags = new FlowPathFlags();
736 flowPathFlags.setFlags(FlowPathFlags.DISCARD_FIRST_HOP_ENTRY);
737 flowPath.setFlowPathFlags(flowPathFlags);
738
739 // Create the DataPath object: dstSwitchPort
740 SwitchPort dstPort = new SwitchPort();
741 dstPort.setDpid(new Dpid(dstInterface.getDpid()));
742 dstPort.setPort(new Port(dstInterface.getPort()));
743
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200744 for (Interface srcInterface : interfaces.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800745
Jonathan Hart45107222013-10-22 17:35:04 -0700746 if (dstInterface.equals(srcInterface)){
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200747 continue;
748 }
pingping-linba5c52f2014-02-11 16:52:01 -0800749
750 // Create flowPath FlowId
pingping-linba5c52f2014-02-11 16:52:01 -0800751 flowPath.setFlowId(new FlowId());
752
753 // Create the DataPath object: srcSwitchPort
754 SwitchPort srcPort = new SwitchPort();
755 srcPort.setDpid(new Dpid(srcInterface.getDpid()));
756 srcPort.setPort(new Port(srcInterface.getPort()));
757
758 DataPath dataPath = new DataPath();
759 dataPath.setSrcPort(srcPort);
760 dataPath.setDstPort(dstPort);
761 flowPath.setDataPath(dataPath);
762
763 // Create the Flow Path Match condition(s)
764 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
765 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPv4);
766 flowEntryMatch.enableDstMac(dstMacAddress);
767 flowPath.setFlowEntryMatch(flowEntryMatch);
768
769 // NOTE: No need to add ACTION_OUTPUT. It is implied when creating
770 // Shortest Path Flow, and is always the last action for the Flow Entries
771 log.debug("FlowPath of MAC based forwarding: {}", flowPath.toString());
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700772 // TODO: Add the flow by using the new Path Intent framework
773 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800774 if (flowManagerService.addFlow(flowPath) == null) {
775 log.error("Failed to set up MAC based forwarding path to {}, {}",
776 path.getDstIpAddress().getHostAddress(),dstMacAddress);
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200777 }
778 else {
pingping-linba5c52f2014-02-11 16:52:01 -0800779 log.debug("Successfully set up MAC based forwarding path to {}, {}",
780 path.getDstIpAddress().getHostAddress(),dstMacAddress);
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200781 }
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700782 */
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200783 }
784 }
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200785
pingping-linba5c52f2014-02-11 16:52:01 -0800786 /**
787 * Pre-actively install all BGP traffic paths from BGP host attachment point
788 * in SDN network to all the virtual gateways to BGP peers in other networks
789 */
790 private void setupBgpPaths(){
791
792 for (BgpPeer bgpPeer : bgpPeers.values()){
793
794 FlowPath flowPath = new FlowPath();
795 flowPath.setInstallerId(new CallerId("SDNIP"));
796
797 // Set flowPath FlowPathType and FlowPathUserState
798 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
799 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
800
801 // Install flow paths between BGPd and its peers
802 // There is no need to set the FlowPathFlags
803 flowPath.setFlowPathFlags(new FlowPathFlags(0));
804
805 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
806
pingping-linba5c52f2014-02-11 16:52:01 -0800807 // Create the Flow Path Match condition(s)
808 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
809 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPv4);
810
811 // Match both source address and dest address
812 IPv4Net dstIPv4Net= new IPv4Net(bgpPeer.getIpAddress().getHostAddress()+"/32");
813 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
814
815 IPv4Net srcIPv4Net= new IPv4Net(peerInterface.getIpAddress().getHostAddress()+"/32");
816 flowEntryMatch.enableSrcIPv4Net(srcIPv4Net);
817
818 // Match TCP protocol
819 flowEntryMatch.enableIpProto(IPv4.PROTOCOL_TCP);
820
821 // Match destination TCP port
822 flowEntryMatch.enableDstTcpUdpPort(BGP_PORT);
823 flowPath.setFlowEntryMatch(flowEntryMatch);
824
825 /**
826 * Create the DataPath: BGP -> BGP peer
827 */
828 // Flow path for src-TCP-port
829 DataPath dataPath = new DataPath();
830
831 SwitchPort srcPort = new SwitchPort();
832 srcPort.setDpid(bgpdAttachmentPoint.dpid());
833 srcPort.setPort(bgpdAttachmentPoint.port());
834 dataPath.setSrcPort(srcPort);
835
836 SwitchPort dstPort = new SwitchPort();
837 dstPort.setDpid(new Dpid(peerInterface.getDpid()));
838 dstPort.setPort(new Port(peerInterface.getSwitchPort().port()));
839 dataPath.setDstPort(dstPort);
840
841 flowPath.setDataPath(dataPath);
842
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700843 // TODO: Add the flow by using the new Path Intent framework
844 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800845 if (flowManagerService.addFlow(flowPath) == null) {
846 log.error("Failed to set up path BGP -> peer {}"+"; dst-TCP-port:179",
847 bgpPeer.getIpAddress().getHostAddress());
848 }
849 else {
850 log.debug("Successfully set up path BGP -> peer {}"+"; dst-TCP-port:179",
851 bgpPeer.getIpAddress().getHostAddress());
852 }
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700853 */
pingping-linba5c52f2014-02-11 16:52:01 -0800854
855 // Disable dst-TCP-port, and set src-TCP-port
856 flowEntryMatch.disableDstTcpUdpPort();
857 flowEntryMatch.enableSrcTcpUdpPort(BGP_PORT);
858 flowPath.setFlowEntryMatch(flowEntryMatch);
859
860 // Create a new FlowId
pingping-linba5c52f2014-02-11 16:52:01 -0800861 flowPath.setFlowId(new FlowId());
862
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700863 // TODO: Add the flow by using the new Path Intent framework
864 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800865 if (flowManagerService.addFlow(flowPath) == null) {
866 log.error("Failed to set up path BGP -> Peer {}" + "; src-TCP-port:179",
867 bgpPeer.getIpAddress().getHostAddress());
868 }
869 else {
870 log.debug("Successfully set up path BGP -> Peer {}" + "; src-TCP-port:179",
871 bgpPeer.getIpAddress().getHostAddress());
872 }
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700873 */
pingping-linba5c52f2014-02-11 16:52:01 -0800874
875 /**
876 * Create the DataPath: BGP <-BGP peer
877 */
878 // Reversed BGP flow path for src-TCP-port
pingping-linba5c52f2014-02-11 16:52:01 -0800879 flowPath.setFlowId(new FlowId());
880
881 DataPath reverse_dataPath = new DataPath();
882
883 SwitchPort reverse_dstPort = new SwitchPort();
884 reverse_dstPort.setDpid(bgpdAttachmentPoint.dpid());
885 reverse_dstPort.setPort(bgpdAttachmentPoint.port());
886 reverse_dataPath.setDstPort(reverse_dstPort);
887
888 SwitchPort reverse_srcPort = new SwitchPort();
889 reverse_srcPort.setDpid(new Dpid(peerInterface.getDpid()));
890 reverse_srcPort.setPort(new Port(peerInterface.getSwitchPort().port()));
891 reverse_dataPath.setSrcPort(reverse_srcPort);
892 flowPath.setDataPath(reverse_dataPath);
893
894 // reverse the dst IP and src IP addresses
895 flowEntryMatch.enableDstIPv4Net(srcIPv4Net);
896 flowEntryMatch.enableSrcIPv4Net(dstIPv4Net);
897 flowPath.setFlowEntryMatch(flowEntryMatch);
898
899 log.debug("Reversed BGP FlowPath: {}", flowPath.toString());
900
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700901 // TODO: Add the flow by using the new Path Intent framework
902 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800903 if (flowManagerService.addFlow(flowPath) == null) {
904
905 log.error("Failed to set up path BGP <- Peer {}" + "; src-TCP-port:179",
906 bgpPeer.getIpAddress().getHostAddress());
907 }
908 else {
909 log.debug("Successfully set up path BGP <- Peer {}" + "; src-TCP-port:179",
910 bgpPeer.getIpAddress().getHostAddress());
911 }
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700912 */
pingping-linba5c52f2014-02-11 16:52:01 -0800913
914 // Reversed BGP flow path for dst-TCP-port
pingping-linba5c52f2014-02-11 16:52:01 -0800915 flowPath.setFlowId(new FlowId());
916
917 // Disable src-TCP-port, and set the dst-TCP-port
918 flowEntryMatch.disableSrcTcpUdpPort();
919 flowEntryMatch.enableDstTcpUdpPort(BGP_PORT);
920 flowPath.setFlowEntryMatch(flowEntryMatch);
921
922 log.debug("Reversed BGP FlowPath: {}", flowPath.toString());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700923
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700924 // TODO: Add the flow by using the new Path Intent framework
925 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800926 if (flowManagerService.addFlow(flowPath) == null) {
927 log.error("Failed to setting up path BGP <- Peer {}" + "; dst-TCP-port:179",
928 bgpPeer.getIpAddress().getHostAddress());
929 }
930 else {
931 log.debug("Successfully setting up path BGP <- Peer {}" + "; dst-TCP-port:179",
932 bgpPeer.getIpAddress().getHostAddress());
933 }
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700934 */
pingping-linba5c52f2014-02-11 16:52:01 -0800935
936 /**
937 * ICMP paths between BGPd and its peers
938 */
939 //match ICMP protocol BGP <- Peer
pingping-linba5c52f2014-02-11 16:52:01 -0800940 flowPath.setFlowId(new FlowId());
941
942 flowEntryMatch.enableIpProto(IPv4.PROTOCOL_ICMP);
943 flowEntryMatch.disableSrcTcpUdpPort();
944 flowEntryMatch.disableDstTcpUdpPort();
945
946 flowPath.setFlowEntryMatch(flowEntryMatch);
947
948 flowPath.setDataPath(reverse_dataPath);
949
950 log.debug("Reversed ICMP FlowPath: {}", flowPath.toString());
951
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700952 // TODO: Add the flow by using the new Path Intent framework
953 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800954 if (flowManagerService.addFlow(flowPath) == null) {
955
956 log.error("Failed to set up ICMP path BGP <- Peer {}",
957 bgpPeer.getIpAddress().getHostAddress());
958 }
959 else {
960 log.debug("Successfully set up ICMP path BGP <- Peer {}",
961 bgpPeer.getIpAddress().getHostAddress());
962 }
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700963 */
pingping-linba5c52f2014-02-11 16:52:01 -0800964
965 //match ICMP protocol BGP -> Peer
pingping-linba5c52f2014-02-11 16:52:01 -0800966 flowPath.setFlowId(new FlowId());
967
968 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
969 flowEntryMatch.enableSrcIPv4Net(srcIPv4Net);
970 flowPath.setFlowEntryMatch(flowEntryMatch);
971
972 flowPath.setDataPath(dataPath);
973
974 log.debug("ICMP flowPath: {}", flowPath.toString());
975
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700976 // TODO: Add the flow by using the new Path Intent framework
977 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800978 if (flowManagerService.addFlow(flowPath) == null) {
979
980 log.error("Failed to set up ICMP path BGP -> Peer {}",
981 bgpPeer.getIpAddress().getHostAddress());
982 }
983 else {
984 log.debug("Successfully set up ICMP path BGP -> Peer {}",
985 bgpPeer.getIpAddress().getHostAddress());
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200986 }
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700987 */
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200988 }
989 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700990
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200991 @Override
Jonathan Hartabad6a52013-09-30 18:17:21 +1300992 public void arpResponse(InetAddress ipAddress, MACAddress macAddress) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700993 log.debug("Received ARP response: {} => {}",
Jonathan Hartabad6a52013-09-30 18:17:21 +1300994 ipAddress.getHostAddress(), macAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700995
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200996 /*
997 * We synchronize on this to prevent changes to the ptree while we're pushing
998 * flows to the switches. If the ptree changes, the ptree and switches
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700999 * could get out of sync.
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001000 */
1001 synchronized (this) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001002 Path path = pathsWaitingOnArp.remove(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001003
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001004 if (path != null) {
Jonathan Hart309889c2013-08-13 23:26:24 +12001005 log.debug("Pushing path to {} at {} on {}", new Object[] {
Jonathan Hartabad6a52013-09-30 18:17:21 +13001006 path.getDstIpAddress().getHostAddress(), macAddress,
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001007 path.getDstInterface().getSwitchPort()});
1008 //These paths should always be to BGP peers. Paths to non-peers are
1009 //handled once the first prefix is ready to push
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001010 if (pushedPaths.containsKey(path.getDstIpAddress())) {
Jonathan Hart309889c2013-08-13 23:26:24 +12001011 //A path already got pushed to this endpoint while we were waiting
1012 //for ARP. We'll copy over the permanent attribute if it is set on this path.
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001013 if (path.isPermanent()) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001014 pushedPaths.get(path.getDstIpAddress()).setPermanent();
Jonathan Hart309889c2013-08-13 23:26:24 +12001015 }
1016 }
1017 else {
Jonathan Hartabad6a52013-09-30 18:17:21 +13001018 calculateAndPushPath(path, macAddress);
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001019 pushedPaths.put(path.getDstIpAddress(), path);
Jonathan Hart309889c2013-08-13 23:26:24 +12001020 }
1021 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001022
Jonathan Hart309889c2013-08-13 23:26:24 +12001023 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001024
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001025 for (RibUpdate update : prefixesToPush) {
1026 //These will always be adds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001027
1028 RibEntry rib = ptree.lookup(update.getPrefix());
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001029 if (rib != null && rib.equals(update.getRibEntry())) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001030 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001031 rib.getNextHop().getHostAddress());
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001032 //We only push prefix flows if the prefix is still in the ptree
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001033 //and the next hop is the same as our update. The prefix could
1034 //have been removed while we were waiting for the ARP, or the
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001035 //next hop could have changed.
Jonathan Hart309889c2013-08-13 23:26:24 +12001036 _processRibAdd(update);
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001037 } else {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001038 log.debug("Received ARP response, but {},{} is no longer in ptree",
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001039 update.getPrefix(), update.getRibEntry());
1040 }
1041 }
Jonathan Hart0ee0f022013-08-03 22:21:54 +12001042 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +12001043 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001044
pingping-linba5c52f2014-02-11 16:52:01 -08001045 //TODO wait the priority module of the flow Manager
Jonathan Hartc82051c2013-08-24 15:12:20 +12001046 private void setupArpFlows() {
1047 OFMatch match = new OFMatch();
1048 match.setDataLayerType(Ethernet.TYPE_ARP);
1049 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001050
Jonathan Hartc82051c2013-08-24 15:12:20 +12001051 OFFlowMod fm = new OFFlowMod();
1052 fm.setMatch(match);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001053
Jonathan Hartc82051c2013-08-24 15:12:20 +12001054 OFActionOutput action = new OFActionOutput();
1055 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1056 action.setMaxLength((short)0xffff);
1057 List<OFAction> actions = new ArrayList<OFAction>(1);
1058 actions.add(action);
1059 fm.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001060
Jonathan Hartc82051c2013-08-24 15:12:20 +12001061 fm.setIdleTimeout((short)0)
pingping-linba5c52f2014-02-11 16:52:01 -08001062 .setHardTimeout((short)0)
1063 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1064 .setCookie(0)
1065 .setCommand(OFFlowMod.OFPFC_ADD)
1066 .setPriority(ARP_PRIORITY)
Jonathan Hartc82051c2013-08-24 15:12:20 +12001067 .setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001068
Jonathan Hartc82051c2013-08-24 15:12:20 +12001069 for (String strdpid : switches){
Jonathan Hart1912afc2013-10-11 12:02:44 +13001070 flowCache.write(HexString.toLong(strdpid), fm);
Jonathan Hartc82051c2013-08-24 15:12:20 +12001071 }
1072 }
pingping-linba5c52f2014-02-11 16:52:01 -08001073 //TODO need update, waiting for the priority feature from flow Manager
Jonathan Hartf886fa12013-09-18 14:46:29 +12001074 private void setupDefaultDropFlows() {
1075 OFFlowMod fm = new OFFlowMod();
1076 fm.setMatch(new OFMatch());
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001077 fm.setActions(new ArrayList<OFAction>()); //No action means drop
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001078
Jonathan Hartf886fa12013-09-18 14:46:29 +12001079 fm.setIdleTimeout((short)0)
pingping-linba5c52f2014-02-11 16:52:01 -08001080 .setHardTimeout((short)0)
1081 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1082 .setCookie(0)
1083 .setCommand(OFFlowMod.OFPFC_ADD)
1084 .setPriority((short)0)
Jonathan Hartf886fa12013-09-18 14:46:29 +12001085 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001086
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001087 OFFlowMod fmLLDP;
1088 OFFlowMod fmBDDP;
1089 try {
pingping-linba5c52f2014-02-11 16:52:01 -08001090 fmLLDP = fm.clone();
1091 fmBDDP = fm.clone();
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001092 } catch (CloneNotSupportedException e1) {
1093 log.error("Error cloning flow mod", e1);
1094 return;
1095 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001096
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001097 OFMatch matchLLDP = new OFMatch();
Stacey Sheldon44433002014-01-21 00:43:09 -05001098 matchLLDP.setDataLayerType((short)0x88cc);
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001099 matchLLDP.setWildcards(matchLLDP.getWildcards() & ~ OFMatch.OFPFW_DL_TYPE);
1100 fmLLDP.setMatch(matchLLDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001101
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001102 OFMatch matchBDDP = new OFMatch();
Stacey Sheldon44433002014-01-21 00:43:09 -05001103 matchBDDP.setDataLayerType((short)0x8942);
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001104 matchBDDP.setWildcards(matchBDDP.getWildcards() & ~ OFMatch.OFPFW_DL_TYPE);
1105 fmBDDP.setMatch(matchBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001106
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001107 OFActionOutput action = new OFActionOutput();
1108 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1109 action.setMaxLength((short)0xffff);
1110 List<OFAction> actions = new ArrayList<OFAction>(1);
1111 actions.add(action);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001112
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001113 fmLLDP.setActions(actions);
1114 fmBDDP.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001115
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001116 fmLLDP.setPriority(ARP_PRIORITY);
1117 fmLLDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1118 fmBDDP.setPriority(ARP_PRIORITY);
1119 fmBDDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001120
1121 List<OFFlowMod> flowModList = new ArrayList<OFFlowMod>(3);
Jonathan Hart1912afc2013-10-11 12:02:44 +13001122 flowModList.add(fm);
1123 flowModList.add(fmLLDP);
1124 flowModList.add(fmBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001125
Jonathan Hartf886fa12013-09-18 14:46:29 +12001126 for (String strdpid : switches){
Jonathan Hart1912afc2013-10-11 12:02:44 +13001127 flowCache.write(HexString.toLong(strdpid), flowModList);
Jonathan Hartf886fa12013-09-18 14:46:29 +12001128 }
1129 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001130
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001131 private void beginRouting(){
1132 log.debug("Topology is now ready, beginning routing function");
Pavlin Radoslavov1237e392014-03-20 16:24:06 -07001133 // TODO: Fix for the new Topology Network Graph
1134 // topology = topologyNetService.newDatabaseTopology();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001135
pingping-linba5c52f2014-02-11 16:52:01 -08001136 // Wait Pavlin's API. We need the following functions.
1137 /*setupArpFlows();
1138 setupDefaultDropFlows();*/
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001139
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001140 setupBgpPaths();
Jonathan Hart98957bf2013-07-01 14:49:24 +12001141 setupFullMesh();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001142
Jonathan Harte7694532013-09-12 12:34:46 +12001143 //Suppress link discovery on external-facing router ports
1144 for (Interface intf : interfaces.values()) {
1145 linkDiscoveryService.AddToSuppressLLDPs(intf.getDpid(), intf.getPort());
1146 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001147
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001148 bgpUpdatesExecutor.execute(new Runnable() {
1149 @Override
1150 public void run() {
1151 doUpdatesThread();
1152 }
1153 });
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001154 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001155
pingping-linba5c52f2014-02-11 16:52:01 -08001156 // Before inserting the paths for BGP traffic, we should check
1157 // whether all the switches in the configure file are discovered by onos.
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001158 private void checkSwitchesConnected(){
1159 for (String dpid : switches){
Pavlin Radoslavov5fe71882014-03-21 16:27:21 -07001160 // TODO: Fix the code below after topoSwitchSerice was removed
1161 /*
pingping-linba5c52f2014-02-11 16:52:01 -08001162 Iterator<ISwitchObject> activeSwitches = topoSwitchService.
1163 getActiveSwitches().iterator();
1164 while(activeSwitches.hasNext())
1165 {
1166 ISwitchObject switchObject = activeSwitches.next();
1167 if (switchObject.getDPID().equals(dpid)) {
1168 break;
1169 }
1170 if(activeSwitches.hasNext() == false) {
1171 log.debug("Not all switches are here yet");
1172 return;
1173 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001174 }
Pavlin Radoslavov5fe71882014-03-21 16:27:21 -07001175 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001176 }
1177 switchesConnected = true;
1178 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001179
Jonathan Hartc824ad02013-07-03 15:58:45 +12001180 //Actually we only need to go half way round to verify full mesh connectivity
1181 //(n^2)/2
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001182 private void checkTopologyReady(){
Jonathan Hartc824ad02013-07-03 15:58:45 +12001183 for (Interface dstInterface : interfaces.values()) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001184 for (Interface srcInterface : interfaces.values()) {
Jonathan Hart45107222013-10-22 17:35:04 -07001185 if (dstInterface.equals(srcInterface)) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001186 continue;
1187 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001188
Pavlin Radoslavov1237e392014-03-20 16:24:06 -07001189 // TODO: Fix for the new Topology Network Graph
1190 /*
Pavlin Radoslavov15954d42013-10-19 15:29:04 -07001191 DataPath shortestPath = topologyNetService.getDatabaseShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +12001192 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001193
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001194 if (shortestPath == null){
1195 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +12001196 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001197 return;
1198 }
Pavlin Radoslavov1237e392014-03-20 16:24:06 -07001199 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001200 }
1201 }
1202 topologyReady = true;
1203 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001204
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001205 private void checkStatus(){
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001206 if (!switchesConnected){
1207 checkSwitchesConnected();
1208 }
1209 boolean oldTopologyReadyStatus = topologyReady;
1210 if (switchesConnected && !topologyReady){
1211 checkTopologyReady();
1212 }
1213 if (!oldTopologyReadyStatus && topologyReady){
1214 beginRouting();
1215 }
1216 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001217
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001218 private void doUpdatesThread() {
1219 boolean interrupted = false;
1220 try {
1221 while (true) {
1222 try {
1223 RibUpdate update = ribUpdates.take();
1224 switch (update.getOperation()){
1225 case UPDATE:
Jonathan Harte4c98692013-10-18 17:40:03 -07001226 if (validateUpdate(update)) {
1227 processRibAdd(update);
1228 }
1229 else {
1230 log.debug("Rib UPDATE out of order: {} via {}",
1231 update.getPrefix(), update.getRibEntry().getNextHop());
1232 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001233 break;
1234 case DELETE:
Jonathan Harte4c98692013-10-18 17:40:03 -07001235 if (validateUpdate(update)) {
1236 processRibDelete(update);
1237 }
1238 else {
1239 log.debug("Rib DELETE out of order: {} via {}",
1240 update.getPrefix(), update.getRibEntry().getNextHop());
1241 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001242 break;
1243 }
1244 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001245 log.debug("Interrupted while taking from updates queue", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001246 interrupted = true;
Jonathan Hart309889c2013-08-13 23:26:24 +12001247 } catch (Exception e) {
1248 log.debug("exception", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001249 }
1250 }
1251 } finally {
1252 if (interrupted) {
1253 Thread.currentThread().interrupt();
1254 }
1255 }
1256 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001257
Jonathan Harte4c98692013-10-18 17:40:03 -07001258 private boolean validateUpdate(RibUpdate update) {
1259 RibEntry newEntry = update.getRibEntry();
1260 RibEntry oldEntry = ptree.lookup(update.getPrefix());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001261
Jonathan Harte4c98692013-10-18 17:40:03 -07001262 //If there is no existing entry we must assume this is the most recent
1263 //update. However this might not always be the case as we might have a
1264 //POST then DELETE reordering.
1265 //if (oldEntry == null || !newEntry.getNextHop().equals(oldEntry.getNextHop())) {
1266 if (oldEntry == null) {
1267 return true;
1268 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001269
Jonathan Harte4c98692013-10-18 17:40:03 -07001270 // This handles the case where routes are gathered in the initial
1271 // request because they don't have sequence number info
1272 if (newEntry.getSysUpTime() == -1 && newEntry.getSequenceNum() == -1) {
1273 return true;
1274 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001275
Jonathan Harte4c98692013-10-18 17:40:03 -07001276 if (newEntry.getSysUpTime() > oldEntry.getSysUpTime()) {
1277 return true;
1278 }
1279 else if (newEntry.getSysUpTime() == oldEntry.getSysUpTime()) {
1280 if (newEntry.getSequenceNum() > oldEntry.getSequenceNum()) {
1281 return true;
1282 }
1283 else {
1284 return false;
1285 }
1286 }
1287 else {
1288 return false;
1289 }
1290 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001291
Jonathan Hart02a59e42014-03-26 18:50:23 -07001292 // The code below should be reimplemented after removal of Floodlight's
1293 // ITopologyService API. It should be implemented on top of network graph
1294 // notifications. (It was pretty hacky anyway...)
1295 /*
pingping-lina2cbfad2013-03-07 08:39:21 +08001296 @Override
Jonathan Hart64c0b202013-08-20 15:45:07 +12001297 public void topologyChanged() {
1298 if (topologyReady) {
1299 return;
1300 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001301
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001302 boolean refreshNeeded = false;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -07001303 for (LDUpdate ldu : topologyService.getLastLinkUpdates()){
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001304 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1305 //We don't need to recalculate anything for just link updates
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001306 //They happen very frequently
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001307 refreshNeeded = true;
1308 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001309
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001310 log.debug("Topo change {}", ldu.getOperation());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001311
Jonathan Hart98957bf2013-07-01 14:49:24 +12001312 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1313 synchronized (linkUpdates) {
1314 linkUpdates.add(ldu);
1315 }
1316 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001317 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001318
Jonathan Hart64c0b202013-08-20 15:45:07 +12001319 if (refreshNeeded && !topologyReady){
Jonathan Hart98957bf2013-07-01 14:49:24 +12001320 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
pingping-lina2cbfad2013-03-07 08:39:21 +08001321 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001322 }
Jonathan Hart02a59e42014-03-26 18:50:23 -07001323 */
Jonathan Hart64c0b202013-08-20 15:45:07 +12001324
1325 @Override
1326 public void addedSwitch(IOFSwitch sw) {
1327 if (!topologyReady) {
1328 sw.clearAllFlowMods();
1329 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001330
Jonathan Hart1912afc2013-10-11 12:02:44 +13001331 flowCache.switchConnected(sw);
Jonathan Hart64c0b202013-08-20 15:45:07 +12001332 }
1333
1334 @Override
Jonathan Hart08ee8522013-09-22 17:34:43 +12001335 public void removedSwitch(IOFSwitch sw) {}
Jonathan Hart64c0b202013-08-20 15:45:07 +12001336
1337 @Override
Jonathan Hart08ee8522013-09-22 17:34:43 +12001338 public void switchPortChanged(Long switchId) {}
Jonathan Hart64c0b202013-08-20 15:45:07 +12001339
1340 @Override
1341 public String getName() {
Jonathan Hart08ee8522013-09-22 17:34:43 +12001342 return "BgpRoute";
1343 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001344
Jonathan Hart08ee8522013-09-22 17:34:43 +12001345 /*
Jonathan Harta8887642013-10-28 13:46:54 -07001346 * IConfigInfoService methods
Jonathan Hart08ee8522013-09-22 17:34:43 +12001347 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001348
Jonathan Hart08ee8522013-09-22 17:34:43 +12001349 @Override
1350 public boolean isInterfaceAddress(InetAddress address) {
1351 Interface intf = interfacePtrie.match(new Prefix(address.getAddress(), 32));
1352 return (intf != null && intf.getIpAddress().equals(address));
1353 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001354
Jonathan Hart08ee8522013-09-22 17:34:43 +12001355 @Override
1356 public boolean inConnectedNetwork(InetAddress address) {
1357 Interface intf = interfacePtrie.match(new Prefix(address.getAddress(), 32));
1358 return (intf != null && !intf.getIpAddress().equals(address));
1359 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001360
Jonathan Hart08ee8522013-09-22 17:34:43 +12001361 @Override
1362 public boolean fromExternalNetwork(long inDpid, short inPort) {
1363 for (Interface intf : interfaces.values()) {
1364 if (intf.getDpid() == inDpid && intf.getPort() == inPort) {
1365 return true;
1366 }
1367 }
1368 return false;
1369 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001370
Jonathan Hart08ee8522013-09-22 17:34:43 +12001371 @Override
1372 public Interface getOutgoingInterface(InetAddress dstIpAddress) {
1373 return interfacePtrie.match(new Prefix(dstIpAddress.getAddress(), 32));
1374 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001375
Jonathan Hart08ee8522013-09-22 17:34:43 +12001376 @Override
1377 public boolean hasLayer3Configuration() {
1378 return !interfaces.isEmpty();
1379 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001380
Jonathan Hart08ee8522013-09-22 17:34:43 +12001381 @Override
1382 public MACAddress getRouterMacAddress() {
1383 return bgpdMacAddress;
Jonathan Hart64c0b202013-08-20 15:45:07 +12001384 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001385
Jonathan Harta8887642013-10-28 13:46:54 -07001386 @Override
1387 public short getVlan() {
1388 return vlan;
1389 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001390}