blob: 7eac308ce233eeb3958c14184f85390e90a5b80b [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;
pingping-linba5c52f2014-02-11 16:52:01 -080036import net.onrc.onos.ofcontroller.core.IDeviceStorage;
37import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IDeviceObject;
38import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
Jonathan Hart98957bf2013-07-01 14:49:24 +120039import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoLinkService;
pingping-linba5c52f2014-02-11 16:52:01 -080040import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoSwitchService;
Jonathan Hartebba1e12013-10-29 11:37:02 -070041import net.onrc.onos.ofcontroller.core.config.IConfigInfoService;
pingping-linba5c52f2014-02-11 16:52:01 -080042import net.onrc.onos.ofcontroller.core.internal.DeviceStorageImpl;
Jonathan Hart98957bf2013-07-01 14:49:24 +120043import net.onrc.onos.ofcontroller.core.internal.TopoLinkServiceImpl;
pingping-linba5c52f2014-02-11 16:52:01 -080044import net.onrc.onos.ofcontroller.core.internal.TopoSwitchServiceImpl;
45import net.onrc.onos.ofcontroller.flowmanager.IFlowService;
HIGUCHI Yutaa56fbde2013-06-17 14:26:05 -070046import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery;
47import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery.LDUpdate;
Jonathan Harte7694532013-09-12 12:34:46 +120048import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscoveryService;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120049import net.onrc.onos.ofcontroller.proxyarp.IArpRequester;
pingping-linba5c52f2014-02-11 16:52:01 -080050import net.onrc.onos.ofcontroller.proxyarp.IProxyArpService;
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -070051import net.onrc.onos.ofcontroller.topology.ITopologyNetService;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070052import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavove1b37bc2013-10-16 03:57:06 -070053import net.onrc.onos.ofcontroller.topology.TopologyManager;
pingping-linba5c52f2014-02-11 16:52:01 -080054import net.onrc.onos.ofcontroller.util.CallerId;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070055import net.onrc.onos.ofcontroller.util.DataPath;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120056import net.onrc.onos.ofcontroller.util.Dpid;
pingping-linba5c52f2014-02-11 16:52:01 -080057import net.onrc.onos.ofcontroller.util.FlowEntryAction;
58import net.onrc.onos.ofcontroller.util.FlowEntryActions;
59import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
60import net.onrc.onos.ofcontroller.util.FlowId;
61import net.onrc.onos.ofcontroller.util.FlowPath;
62import net.onrc.onos.ofcontroller.util.FlowPathFlags;
63import net.onrc.onos.ofcontroller.util.FlowPathType;
64import net.onrc.onos.ofcontroller.util.FlowPathUserState;
65import net.onrc.onos.ofcontroller.util.IPv4Net;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070066import net.onrc.onos.ofcontroller.util.Port;
67import net.onrc.onos.ofcontroller.util.SwitchPort;
pingping-line2a09ca2013-03-23 09:33:58 +080068import net.sf.json.JSONArray;
69import net.sf.json.JSONObject;
70import net.sf.json.JSONSerializer;
pingping-lina2cbfad2013-03-07 08:39:21 +080071
Jonathan Hartd1f23252013-06-13 15:17:05 +120072import org.codehaus.jackson.JsonParseException;
73import org.codehaus.jackson.map.JsonMappingException;
74import org.codehaus.jackson.map.ObjectMapper;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070075import org.openflow.protocol.OFFlowMod;
76import org.openflow.protocol.OFMatch;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070077import org.openflow.protocol.OFPacketOut;
Jonathan Hart9575cb62013-07-05 13:43:49 +120078import org.openflow.protocol.OFPort;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070079import org.openflow.protocol.action.OFAction;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070080import org.openflow.protocol.action.OFActionOutput;
Jonathan Hart1236a9b2013-06-18 22:10:05 +120081import org.openflow.util.HexString;
pingping-lina2cbfad2013-03-07 08:39:21 +080082import org.slf4j.Logger;
83import org.slf4j.LoggerFactory;
84
Jonathan Hart4dfc3652013-08-02 20:22:36 +120085import com.google.common.collect.HashMultimap;
Jonathan Hart0ee0f022013-08-03 22:21:54 +120086import com.google.common.collect.Multimap;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120087import com.google.common.collect.Multimaps;
88import com.google.common.collect.SetMultimap;
Jonathan Hart309889c2013-08-13 23:26:24 +120089import com.google.common.net.InetAddresses;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120090import com.google.common.util.concurrent.ThreadFactoryBuilder;
91
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070092public class BgpRoute implements IFloodlightModule, IBgpRouteService,
Jonathan Hart64c0b202013-08-20 15:45:07 +120093 ITopologyListener, IArpRequester,
Jonathan Hart7804bea2014-01-07 10:50:52 -080094 IOFSwitchListener, IConfigInfoService {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070095
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -070096 private final static Logger log = LoggerFactory.getLogger(BgpRoute.class);
pingping-lina2cbfad2013-03-07 08:39:21 +080097
Jonathan Hartf247ee72013-10-18 18:57:28 -070098 private IFloodlightProviderService floodlightProvider;
Jonathan Hart3a326122013-10-21 11:51:13 -070099 private ITopologyService topologyService;
Jonathan Hartf247ee72013-10-18 18:57:28 -0700100 private ITopologyNetService topologyNetService;
101 private ILinkDiscoveryService linkDiscoveryService;
102 private IRestApiService restApi;
pingping-linba5c52f2014-02-11 16:52:01 -0800103 private IProxyArpService proxyArp;
104 protected volatile IFlowService flowManagerService;
105 private IDeviceStorage deviceStorage;
106 private ITopoSwitchService topoSwitchService;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700107
Jonathan Hartf247ee72013-10-18 18:57:28 -0700108 private IPatriciaTrie<RibEntry> ptree;
109 private IPatriciaTrie<Interface> interfacePtrie;
110 private BlockingQueue<RibUpdate> ribUpdates;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700111
Jonathan Hartf247ee72013-10-18 18:57:28 -0700112 private String bgpdRestIp;
113 private String routerId;
114 private String configFilename = "config.json";
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700115
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700116 //We need to identify our flows somehow. But like it says in LearningSwitch.java,
117 //the controller/OS should hand out cookie IDs to prevent conflicts.
Jonathan Hartf247ee72013-10-18 18:57:28 -0700118 private final long APP_COOKIE = 0xa0000000000000L;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700119 //Cookie for flows that do L2 forwarding within SDN domain to egress routers
Jonathan Hartf247ee72013-10-18 18:57:28 -0700120 private final long L2_FWD_COOKIE = APP_COOKIE + 1;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700121 //Cookie for flows in ingress switches that rewrite the MAC address
Jonathan Hartf247ee72013-10-18 18:57:28 -0700122 private final long MAC_RW_COOKIE = APP_COOKIE + 2;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200123 //Cookie for flows that setup BGP paths
Jonathan Hartf247ee72013-10-18 18:57:28 -0700124 private final long BGP_COOKIE = APP_COOKIE + 3;
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200125 //Forwarding uses priority 0, and the mac rewrite entries in ingress switches
126 //need to be higher priority than this otherwise the rewrite may not get done
Jonathan Hartf247ee72013-10-18 18:57:28 -0700127 private final short SDNIP_PRIORITY = 10;
128 private final short ARP_PRIORITY = 20;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700129
Jonathan Hartf247ee72013-10-18 18:57:28 -0700130 private final short BGP_PORT = 179;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700131
Jonathan Hartf247ee72013-10-18 18:57:28 -0700132 private final int TOPO_DETECTION_WAIT = 2; //seconds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700133
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200134 //Configuration stuff
Jonathan Hartf247ee72013-10-18 18:57:28 -0700135 private List<String> switches;
136 private Map<String, Interface> interfaces;
137 private Map<InetAddress, BgpPeer> bgpPeers;
138 private SwitchPort bgpdAttachmentPoint;
139 private MACAddress bgpdMacAddress;
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700140 private short vlan;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700141
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200142 //True when all switches have connected
Jonathan Hartf247ee72013-10-18 18:57:28 -0700143 private volatile boolean switchesConnected = false;
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200144 //True when we have a full mesh of shortest paths between gateways
Jonathan Hartf247ee72013-10-18 18:57:28 -0700145 private volatile boolean topologyReady = false;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200146
Jonathan Hartf247ee72013-10-18 18:57:28 -0700147 private ArrayList<LDUpdate> linkUpdates;
148 private SingletonTask topologyChangeDetectorTask;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700149
Jonathan Hartf247ee72013-10-18 18:57:28 -0700150 private SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700151
Jonathan Hartf247ee72013-10-18 18:57:28 -0700152 private Map<InetAddress, Path> pathsWaitingOnArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700153
Jonathan Hartf247ee72013-10-18 18:57:28 -0700154 private ExecutorService bgpUpdatesExecutor;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700155
Jonathan Hartf247ee72013-10-18 18:57:28 -0700156 private Map<InetAddress, Path> pushedPaths;
157 private Map<Prefix, Path> prefixToPath;
pingping-linba5c52f2014-02-11 16:52:01 -0800158// private Multimap<Prefix, PushedFlowMod> pushedFlows;
159 private Multimap<Prefix, FlowId> pushedFlowIds;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700160
Jonathan Hart1912afc2013-10-11 12:02:44 +1300161 private FlowCache flowCache;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700162
Jonathan Hart3a326122013-10-21 11:51:13 -0700163 private volatile Topology topology = null;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700164
Jonathan Hartf247ee72013-10-18 18:57:28 -0700165 private class TopologyChangeDetector implements Runnable {
Jonathan Hart98957bf2013-07-01 14:49:24 +1200166 @Override
167 public void run() {
168 log.debug("Running topology change detection task");
169 synchronized (linkUpdates) {
Jonathan Hartc824ad02013-07-03 15:58:45 +1200170 //This is the model the REST API uses to retrieve network graph info
Jonathan Hart98957bf2013-07-01 14:49:24 +1200171 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700172
Jonathan Hart98957bf2013-07-01 14:49:24 +1200173 List<Link> activeLinks = topoLinkService.getActiveLinks();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700174
Jonathan Hart98957bf2013-07-01 14:49:24 +1200175 Iterator<LDUpdate> it = linkUpdates.iterator();
176 while (it.hasNext()){
177 LDUpdate ldu = it.next();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700178 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
Jonathan Hart98957bf2013-07-01 14:49:24 +1200179 ldu.getDst(), ldu.getDstPort());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700180
Jonathan Hart98957bf2013-07-01 14:49:24 +1200181 if (activeLinks.contains(l)){
Jonathan Hart98957bf2013-07-01 14:49:24 +1200182 it.remove();
183 }
184 }
185 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700186
Jonathan Hart64c0b202013-08-20 15:45:07 +1200187 if (!topologyReady) {
188 if (linkUpdates.isEmpty()){
189 //All updates have been seen in network map.
190 //We can check if topology is ready
191 log.debug("No known changes outstanding. Checking topology now");
192 checkStatus();
193 }
194 else {
195 //We know of some link updates that haven't propagated to the database yet
196 log.debug("Some changes not found in network map - {} links missing", linkUpdates.size());
197 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
198 }
Jonathan Hart98957bf2013-07-01 14:49:24 +1200199 }
200 }
201 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700202
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700203 private void readConfiguration(String configFilename){
204 File gatewaysFile = new File(configFilename);
Jonathan Hartd1f23252013-06-13 15:17:05 +1200205 ObjectMapper mapper = new ObjectMapper();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700206
Jonathan Hartd1f23252013-06-13 15:17:05 +1200207 try {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200208 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700209
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200210 switches = config.getSwitches();
Jonathan Hart9575cb62013-07-05 13:43:49 +1200211 interfaces = new HashMap<String, Interface>();
212 for (Interface intf : config.getInterfaces()){
213 interfaces.put(intf.getName(), intf);
214 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200215 bgpPeers = new HashMap<InetAddress, BgpPeer>();
216 for (BgpPeer peer : config.getPeers()){
217 bgpPeers.put(peer.getIpAddress(), peer);
218 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700219
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200220 bgpdAttachmentPoint = new SwitchPort(
221 new Dpid(config.getBgpdAttachmentDpid()),
222 new Port(config.getBgpdAttachmentPort()));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700223
Jonathan Hart2f790d22013-08-15 14:01:24 +1200224 bgpdMacAddress = config.getBgpdMacAddress();
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700225 vlan = config.getVlan();
Jonathan Hartd1f23252013-06-13 15:17:05 +1200226 } catch (JsonParseException e) {
227 log.error("Error in JSON file", e);
228 System.exit(1);
229 } catch (JsonMappingException e) {
230 log.error("Error in JSON file", e);
231 System.exit(1);
232 } catch (IOException e) {
233 log.error("Error reading JSON file", e);
234 System.exit(1);
235 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700236
Jonathan Hartabf10222013-08-13 10:19:34 +1200237 //Populate the interface Patricia Trie
238 for (Interface intf : interfaces.values()) {
239 Prefix prefix = new Prefix(intf.getIpAddress().getAddress(), intf.getPrefixLength());
240 interfacePtrie.put(prefix, intf);
241 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700242 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700243
pingping-lina2cbfad2013-03-07 08:39:21 +0800244 @Override
245 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
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(IBgpRouteService.class);
Jonathan Harta8887642013-10-28 13:46:54 -0700249 l.add(IConfigInfoService.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 Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700255 Map<Class<? extends IFloodlightService>, IFloodlightService> m
Jonathan Hart61ba9372013-05-19 20:10:29 -0700256 = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
pingping-line2a09ca2013-03-23 09:33:58 +0800257 m.put(IBgpRouteService.class, this);
Jonathan Harta8887642013-10-28 13:46:54 -0700258 m.put(IConfigInfoService.class, this);
pingping-lina2cbfad2013-03-07 08:39:21 +0800259 return m;
260 }
261
pingping-lina2cbfad2013-03-07 08:39:21 +0800262 @Override
263 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700264 Collection<Class<? extends IFloodlightService>> l
Jonathan Hart61ba9372013-05-19 20:10:29 -0700265 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800266 l.add(IFloodlightProviderService.class);
267 l.add(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700268 l.add(IRestApiService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800269 return l;
270 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700271
pingping-lina2cbfad2013-03-07 08:39:21 +0800272 @Override
273 public void init(FloodlightModuleContext context)
274 throws FloodlightModuleException {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700275
Jonathan Hart29b972d2013-08-12 23:43:51 +1200276 ptree = new PatriciaTrie<RibEntry>(32);
Jonathan Hartabf10222013-08-13 10:19:34 +1200277 interfacePtrie = new PatriciaTrie<Interface>(32);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700278
pingping-linba5c52f2014-02-11 16:52:01 -0800279 ribUpdates = new LinkedBlockingQueue<RibUpdate>();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700280
pingping-lina2cbfad2013-03-07 08:39:21 +0800281 // Register floodlight provider and REST handler.
282 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700283 topologyService = context.getServiceImpl(ITopologyService.class);
Jonathan Harte7694532013-09-12 12:34:46 +1200284 linkDiscoveryService = context.getServiceImpl(ILinkDiscoveryService.class);
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200285 restApi = context.getServiceImpl(IRestApiService.class);
pingping-linba5c52f2014-02-11 16:52:01 -0800286 flowManagerService = context.getServiceImpl(IFlowService.class);
287 proxyArp = context.getServiceImpl(IProxyArpService.class);
288
289 deviceStorage = new DeviceStorageImpl();
290 deviceStorage.init("", "");
291
Jonathan Hart98957bf2013-07-01 14:49:24 +1200292 linkUpdates = new ArrayList<LDUpdate>();
293 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
294 topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700295
yoshif7424e42013-11-25 22:07:40 -0800296 topologyNetService = new TopologyManager(context);
pingping-linba5c52f2014-02-11 16:52:01 -0800297 topoSwitchService = new TopoSwitchServiceImpl();
298
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200299 pathsWaitingOnArp = new HashMap<InetAddress, Path>();
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200300 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
301 HashMultimap.<InetAddress, RibUpdate>create());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700302
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200303 pushedPaths = new HashMap<InetAddress, Path>();
304 prefixToPath = new HashMap<Prefix, Path>();
pingping-linba5c52f2014-02-11 16:52:01 -0800305// pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
306 pushedFlowIds = HashMultimap.<Prefix, FlowId>create();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700307
Jonathan Hart1912afc2013-10-11 12:02:44 +1300308 flowCache = new FlowCache(floodlightProvider);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700309
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200310 bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
311 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700312
Jonathan Hart61ba9372013-05-19 20:10:29 -0700313 //Read in config values
314 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
315 if (bgpdRestIp == null){
316 log.error("BgpdRestIp property not found in config file");
317 System.exit(1);
318 }
319 else {
320 log.info("BgpdRestIp set to {}", bgpdRestIp);
321 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700322
Jonathan Hart61ba9372013-05-19 20:10:29 -0700323 routerId = context.getConfigParams(this).get("RouterId");
324 if (routerId == null){
325 log.error("RouterId property not found in config file");
326 System.exit(1);
327 }
328 else {
329 log.info("RouterId set to {}", routerId);
330 }
pingping-linba5c52f2014-02-11 16:52:01 -0800331
Jonathan Hart9575cb62013-07-05 13:43:49 +1200332 String configFilenameParameter = context.getConfigParams(this).get("configfile");
333 if (configFilenameParameter != null){
334 configFilename = configFilenameParameter;
335 }
336 log.debug("Config file set to {}", configFilename);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700337
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700338 readConfiguration(configFilename);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200339 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700340
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200341 @Override
342 public void startUp(FloodlightModuleContext context) {
343 restApi.addRestletRoutable(new BgpRouteWebRoutable());
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700344 topologyService.addListener(this);
Jonathan Hart64c0b202013-08-20 15:45:07 +1200345 floodlightProvider.addOFSwitchListener(this);
pingping-linba5c52f2014-02-11 16:52:01 -0800346
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200347 //Retrieve the RIB from BGPd during startup
348 retrieveRib();
pingping-lina2cbfad2013-03-07 08:39:21 +0800349 }
350
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700351 @Override
Jonathan Hart29b972d2013-08-12 23:43:51 +1200352 public IPatriciaTrie<RibEntry> getPtree() {
pingping-lina2cbfad2013-03-07 08:39:21 +0800353 return ptree;
354 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700355
356 @Override
Jonathan Hart61ba9372013-05-19 20:10:29 -0700357 public void clearPtree() {
Jonathan Hart29b972d2013-08-12 23:43:51 +1200358 ptree = new PatriciaTrie<RibEntry>(32);
pingping-line2a09ca2013-03-23 09:33:58 +0800359 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700360
361 @Override
pingping-line2a09ca2013-03-23 09:33:58 +0800362 public String getBGPdRestIp() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700363 return bgpdRestIp;
pingping-line2a09ca2013-03-23 09:33:58 +0800364 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700365
366 @Override
pingping-line2a09ca2013-03-23 09:33:58 +0800367 public String getRouterId() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700368 return routerId;
pingping-line2a09ca2013-03-23 09:33:58 +0800369 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700370
Jonathan Hart61ba9372013-05-19 20:10:29 -0700371 private void retrieveRib(){
372 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
373 String response = RestClient.get(url);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700374
Jonathan Hart61ba9372013-05-19 20:10:29 -0700375 if (response.equals("")){
376 return;
377 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700378
Jonathan Hart61ba9372013-05-19 20:10:29 -0700379 response = response.replaceAll("\"", "'");
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700380 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
Jonathan Hart61ba9372013-05-19 20:10:29 -0700381 JSONArray rib_json_array = jsonObj.getJSONArray("rib");
382 String router_id = jsonObj.getString("router-id");
383
384 int size = rib_json_array.size();
385
386 log.info("Retrived RIB of {} entries from BGPd", size);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700387
Jonathan Hart61ba9372013-05-19 20:10:29 -0700388 for (int j = 0; j < size; j++) {
389 JSONObject second_json_object = rib_json_array.getJSONObject(j);
390 String prefix = second_json_object.getString("prefix");
391 String nexthop = second_json_object.getString("nexthop");
392
393 //insert each rib entry into the local rib;
394 String[] substring = prefix.split("/");
395 String prefix1 = substring[0];
396 String mask1 = substring[1];
397
398 Prefix p;
399 try {
400 p = new Prefix(prefix1, Integer.valueOf(mask1));
401 } catch (NumberFormatException e) {
402 log.warn("Wrong mask format in RIB JSON: {}", mask1);
403 continue;
Jonathan Hart32e18222013-08-07 22:05:42 +1200404 } catch (IllegalArgumentException e1) {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700405 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
406 continue;
407 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700408
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200409 RibEntry rib = new RibEntry(router_id, nexthop);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700410
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200411 try {
412 ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
413 } catch (InterruptedException e) {
414 log.debug("Interrupted while pushing onto update queue");
415 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700416 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700417 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700418
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200419 @Override
420 public void newRibUpdate(RibUpdate update) {
Jonathan Hart9ea31212013-08-12 21:40:34 +1200421 try {
422 ribUpdates.put(update);
423 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200424 log.debug("Interrupted while putting on ribUpdates queue", e);
425 Thread.currentThread().interrupt();
Jonathan Hart9ea31212013-08-12 21:40:34 +1200426 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200427 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700428
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200429 public synchronized void processRibAdd(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200430 Prefix prefix = update.getPrefix();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700431
Jonathan Hart9ea31212013-08-12 21:40:34 +1200432 log.debug("Processing prefix add {}", prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700433
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200434 RibEntry rib = ptree.put(prefix, update.getRibEntry());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700435
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200436 if (rib != null && !rib.equals(update.getRibEntry())) {
Jonathan Hart2f740782013-08-04 00:49:21 +1200437 //There was an existing nexthop for this prefix. This update supersedes that,
438 //so we need to remove the old flows for this prefix from the switches
Jonathan Hart309889c2013-08-13 23:26:24 +1200439 _processDeletePrefix(prefix, rib);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200440 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700441
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200442 if (update.getRibEntry().getNextHop().equals(
443 InetAddresses.forString("0.0.0.0"))) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200444 //Route originated by SDN domain
445 //We don't handle these at the moment
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700446 log.debug("Own route {} to {}", prefix,
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200447 update.getRibEntry().getNextHop().getHostAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200448 return;
449 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700450
Jonathan Hart309889c2013-08-13 23:26:24 +1200451 _processRibAdd(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200452 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700453
Jonathan Hart309889c2013-08-13 23:26:24 +1200454 private void _processRibAdd(RibUpdate update) {
455 Prefix prefix = update.getPrefix();
456 RibEntry rib = update.getRibEntry();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700457
Jonathan Hart309889c2013-08-13 23:26:24 +1200458 InetAddress dstIpAddress = rib.getNextHop();
pingping-linba5c52f2014-02-11 16:52:01 -0800459 MACAddress nextHopMacAddress;
460
461 // See if we know the MAC address of the next hop
462 // TODO if we do not treat the next hop as a device in the future, we need to update this
463 IDeviceObject nextHopDevice =
464 deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(dstIpAddress));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700465
pingping-linba5c52f2014-02-11 16:52:01 -0800466 if (nextHopDevice == null){
467 log.debug("NextHopDevice for IP: {} is null", dstIpAddress);
468 prefixesWaitingOnArp.put(dstIpAddress,
469 new RibUpdate(Operation.UPDATE, prefix, rib));
470 proxyArp.sendArpRequest(dstIpAddress, this, true);
471 return;
472
473 }
474 nextHopMacAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700475
pingping-linba5c52f2014-02-11 16:52:01 -0800476 // Find the attachment point (egress interface) of the next hop
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200477 Interface egressInterface = null;
Jonathan Hart309889c2013-08-13 23:26:24 +1200478 if (bgpPeers.containsKey(dstIpAddress)) {
479 //Route to a peer
480 log.debug("Route to peer {}", dstIpAddress);
481 BgpPeer peer = bgpPeers.get(dstIpAddress);
482 egressInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart309889c2013-08-13 23:26:24 +1200483 }
484 else {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200485 //Route to non-peer
Jonathan Hart309889c2013-08-13 23:26:24 +1200486 log.debug("Route to non-peer {}", dstIpAddress);
487 egressInterface = interfacePtrie.match(
488 new Prefix(dstIpAddress.getAddress(), 32));
489 if (egressInterface == null) {
490 log.warn("No outgoing interface found for {}", dstIpAddress.getHostAddress());
491 return;
492 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200493 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700494
Jonathan Hart309889c2013-08-13 23:26:24 +1200495 if (nextHopMacAddress == null) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700496 prefixesWaitingOnArp.put(dstIpAddress,
Jonathan Hart309889c2013-08-13 23:26:24 +1200497 new RibUpdate(Operation.UPDATE, prefix, rib));
498 proxyArp.sendArpRequest(dstIpAddress, this, true);
499 return;
500 }
501 else {
502 if (!bgpPeers.containsKey(dstIpAddress)) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200503 //If the prefix is for a non-peer we need to ensure there's a path,
504 //and push one if there isn't.
505 Path path = pushedPaths.get(dstIpAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200506 if (path == null) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200507 path = new Path(egressInterface, dstIpAddress);
Jonathan Hartabad6a52013-09-30 18:17:21 +1300508 calculateAndPushPath(path, nextHopMacAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200509 pushedPaths.put(dstIpAddress, path);
510 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700511
Jonathan Hart309889c2013-08-13 23:26:24 +1200512 path.incrementUsers();
513 prefixToPath.put(prefix, path);
514 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700515
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200516 //For all prefixes we need to add the first-hop mac-rewriting flows
Jonathan Hart309889c2013-08-13 23:26:24 +1200517 addPrefixFlows(prefix, egressInterface, nextHopMacAddress);
518 }
519 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700520
pingping-linba5c52f2014-02-11 16:52:01 -0800521 /**
522 * Add a flow to match dst-IP prefix and rewrite MAC for one IP prefix
523 * to all other border switches
524 */
525 private void addPrefixFlows(Prefix prefix, Interface egressInterface,
526 MACAddress nextHopMacAddress) {
Jonathan Harte4c98692013-10-18 17:40:03 -0700527 log.debug("Adding flows for prefix {}, next hop mac {}",
Jonathan Hartabad6a52013-09-30 18:17:21 +1300528 prefix, nextHopMacAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700529
pingping-linba5c52f2014-02-11 16:52:01 -0800530 FlowPath flowPath = new FlowPath();
531 flowPath.setInstallerId(new CallerId("SDNIP"));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700532
pingping-linba5c52f2014-02-11 16:52:01 -0800533 // Set flowPath FlowPathType and FlowPathUserState
534 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
535 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
536
537 // Insert dst-ip prefix based forwarding and MAC rewrite flow entry
538 // only to the first-host switches
539 FlowPathFlags flowPathFlags = new FlowPathFlags();
540 flowPathFlags.setFlags(FlowPathFlags.KEEP_ONLY_FIRST_HOP_ENTRY);
541 flowPath.setFlowPathFlags(flowPathFlags);
542
543 // Create the DataPath object: dstSwitchPort
544 SwitchPort dstPort = new SwitchPort();
545 dstPort.setDpid(new Dpid(egressInterface.getDpid()));
546 dstPort.setPort(new Port(egressInterface.getPort()));
547
548 // We only need one flow mod per switch, so pick one interface on each switch
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200549 Map<Long, Interface> srcInterfaces = new HashMap<Long, Interface>();
550 for (Interface intf : interfaces.values()) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700551 if (!srcInterfaces.containsKey(intf.getDpid())
Jonathan Hart45107222013-10-22 17:35:04 -0700552 && !intf.equals(egressInterface)) {
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200553 srcInterfaces.put(intf.getDpid(), intf);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200554 }
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200555 }
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200556 for (Interface srcInterface : srcInterfaces.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800557
558 if (egressInterface.equals(srcInterface)){
559 continue;
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200560 }
pingping-linba5c52f2014-02-11 16:52:01 -0800561
562 // Create flowPath FlowId
563 //FlowId returnByRefFlowId = new FlowId(flowManagerService.getNextFlowEntryId());
564 //flowPath.setFlowId(returnByRefFlowId);
565 flowPath.setFlowId(new FlowId());
566
567 // Create DataPath object: srcSwitchPort
568 SwitchPort srcPort = new SwitchPort();
569 srcPort.setDpid(new Dpid(srcInterface.getDpid()));
570 srcPort.setPort(new Port(srcInterface.getPort()));
571
572 DataPath dataPath = new DataPath();
573 dataPath.setSrcPort(srcPort);
574 dataPath.setDstPort(dstPort);
575 flowPath.setDataPath(dataPath);
576
577 // Create flow path matching condition(s): IPv4 Prefix
578 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
579 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPv4);
580 IPv4Net dstIPv4Net= new IPv4Net(prefix.toString());
581 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
582 flowPath.setFlowEntryMatch(flowEntryMatch);
Jonathan Hart1912afc2013-10-11 12:02:44 +1300583
584 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800585 * Create the Flow Entry Action(s): dst-MAC rewrite action
Jonathan Hart1912afc2013-10-11 12:02:44 +1300586 */
pingping-linba5c52f2014-02-11 16:52:01 -0800587 FlowEntryActions flowEntryActions = new FlowEntryActions();
588 FlowEntryAction flowEntryAction1 = new FlowEntryAction();
589 flowEntryAction1.setActionSetEthernetDstAddr(nextHopMacAddress);
590 // flowEntryAction1.actionSetEthernetDstAddr(nextHopMacAddress);
591 flowEntryActions.addAction(flowEntryAction1);
592 flowPath.setFlowEntryActions(flowEntryActions);
593
594 // Flow Path installation, only to first hop switches
595 if (flowManagerService.addFlow(flowPath) == null) {
596 log.error("Failed to install flow path to the first hop for " +
597 "prefix: {}, nextHopMacAddress: {}", prefix.getAddress(),
598 nextHopMacAddress);
599 }
600 else {
601 log.debug("Successfully installed flow path to the first hop " +
602 "for prefix: {}, nextHopMacAddress: {}", prefix.getAddress(),
603 nextHopMacAddress);
604
605 pushedFlowIds.put(prefix, flowPath.flowId());
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200606 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200607 }
608 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700609
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200610 public synchronized void processRibDelete(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200611 Prefix prefix = update.getPrefix();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700612
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200613 if (ptree.remove(prefix, update.getRibEntry())) {
614 /*
615 * Only delete flows if an entry was actually removed from the trie.
616 * If no entry was removed, the <prefix, nexthop> wasn't there so
617 * it's probably already been removed and we don't need to do anything
618 */
Jonathan Hart309889c2013-08-13 23:26:24 +1200619 _processDeletePrefix(prefix, update.getRibEntry());
Jonathan Hart309889c2013-08-13 23:26:24 +1200620 }
621 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700622
Jonathan Hart309889c2013-08-13 23:26:24 +1200623 private void _processDeletePrefix(Prefix prefix, RibEntry ribEntry) {
624 deletePrefixFlows(prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700625
Jonathan Hart309889c2013-08-13 23:26:24 +1200626 log.debug("Deleting {} to {}", prefix, ribEntry.getNextHop());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700627
Jonathan Hart309889c2013-08-13 23:26:24 +1200628 if (!bgpPeers.containsKey(ribEntry.getNextHop())) {
629 log.debug("Getting path for route with non-peer nexthop");
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200630 Path path = prefixToPath.remove(prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700631
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200632 if (path != null) {
633 //path could be null if we added to the Ptree but didn't push
634 //flows yet because we were waiting to resolve ARP
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700635
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200636 path.decrementUsers();
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200637 if (path.getUsers() <= 0 && !path.isPermanent()) {
638 deletePath(path);
639 pushedPaths.remove(path.getDstIpAddress());
640 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200641 }
642 }
643 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700644
pingping-linba5c52f2014-02-11 16:52:01 -0800645 // TODO have not tested this module
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200646 private void deletePrefixFlows(Prefix prefix) {
647 log.debug("Deleting flows for prefix {}", prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700648
pingping-linba5c52f2014-02-11 16:52:01 -0800649 Collection<FlowId> flowIds = pushedFlowIds.removeAll(prefix);
650 for (FlowId flowId : flowIds) {
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200651 if (log.isTraceEnabled()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800652 //Trace the flow status by flowPath in the switch before deleting it
653 log.trace("Pushing a DELETE flow mod to flowPath : {}",
654 flowManagerService.getFlow(flowId).toString());
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200655 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700656
pingping-linba5c52f2014-02-11 16:52:01 -0800657 if( flowManagerService.deleteFlow(flowId))
658 {
659 log.debug("Successfully deleted FlowId: {}",flowId);
660 }
661 else
662 {
663 log.debug("Failed to delete FlowId: {}",flowId);
664 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200665 }
666 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700667
pingping-linba5c52f2014-02-11 16:52:01 -0800668 // TODO need to record the path and then delete here
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200669 private void deletePath(Path path) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700670 log.debug("Deleting flows for path to {}",
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200671 path.getDstIpAddress().getHostAddress());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700672
pingping-linba5c52f2014-02-11 16:52:01 -0800673 // TODO need update
674 /*for (PushedFlowMod pfm : path.getFlowMods()) {
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200675 if (log.isTraceEnabled()) {
676 log.trace("Pushing a DELETE flow mod to {}, dst MAC {}",
677 new Object[] {HexString.toHexString(pfm.getDpid()),
678 HexString.toHexString(pfm.getFlowMod().getMatch().getDataLayerDestination())
679 });
680 }
pingping-linba5c52f2014-02-11 16:52:01 -0800681
Jonathan Hart309889c2013-08-13 23:26:24 +1200682 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
pingping-linba5c52f2014-02-11 16:52:01 -0800683 }*/
Jonathan Hart309889c2013-08-13 23:26:24 +1200684 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700685
686
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200687 //TODO test next-hop changes
Jonathan Hart2f740782013-08-04 00:49:21 +1200688 //TODO check delete/add synchronization
pingping-linba5c52f2014-02-11 16:52:01 -0800689
690 /**
691 * On startup, we need to calculate a full mesh of paths between all gateway
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700692 * switches
693 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200694 private void setupFullMesh(){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700695 //For each border router, calculate and install a path from every other
696 //border switch to said border router. However, don't install the entry
697 //in to the first hop switch, as we need to install an entry to rewrite
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700698 //for each prefix received. This will be done later when prefixes have
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700699 //actually been received.
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700700
Jonathan Hartc824ad02013-07-03 15:58:45 +1200701 for (BgpPeer peer : bgpPeers.values()) {
702 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700703
Jonathan Hart309889c2013-08-13 23:26:24 +1200704 //We know there's not already a Path here pushed, because this is
705 //called before all other routing
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200706 Path path = new Path(peerInterface, peer.getIpAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200707 path.setPermanent();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700708
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200709 //See if we know the MAC address of the peer. If not we can't
710 //do anything until we learn it
pingping-linba5c52f2014-02-11 16:52:01 -0800711 MACAddress macAddress;
712 IDeviceObject nextHopDevice =
713 deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(peer.getIpAddress()));
714
715 if(nextHopDevice == null){
716 log.debug("There is no DeviceObject for {}", peer.getIpAddress().getHostAddress());
717 //Put in the pending paths list first
718 pathsWaitingOnArp.put(peer.getIpAddress(), path);
719 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
720 continue;
721 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700722
pingping-linba5c52f2014-02-11 16:52:01 -0800723 macAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
724
Jonathan Hartabad6a52013-09-30 18:17:21 +1300725 if (macAddress == null) {
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200726 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
727 //Put in the pending paths list first
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200728 pathsWaitingOnArp.put(peer.getIpAddress(), path);
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200729 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
730 continue;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700731 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700732
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200733 //If we know the MAC, lets go ahead and push the paths to this peer
Jonathan Hartabad6a52013-09-30 18:17:21 +1300734 calculateAndPushPath(path, macAddress);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700735 }
736 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700737
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200738 private void calculateAndPushPath(Path path, MACAddress dstMacAddress) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200739 Interface dstInterface = path.getDstInterface();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700740
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200741 log.debug("Setting up path to {}, {}", path.getDstIpAddress().getHostAddress(),
742 dstMacAddress);
pingping-linba5c52f2014-02-11 16:52:01 -0800743
744 FlowPath flowPath = new FlowPath();
745
746 flowPath.setInstallerId(new CallerId("SDNIP"));
747
748 // Set flowPath FlowPathType and FlowPathUserState
749 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
750 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
751
752 // Insert the dest-mac based forwarding flow entry to the non-first-hop switches
753 FlowPathFlags flowPathFlags = new FlowPathFlags();
754 flowPathFlags.setFlags(FlowPathFlags.DISCARD_FIRST_HOP_ENTRY);
755 flowPath.setFlowPathFlags(flowPathFlags);
756
757 // Create the DataPath object: dstSwitchPort
758 SwitchPort dstPort = new SwitchPort();
759 dstPort.setDpid(new Dpid(dstInterface.getDpid()));
760 dstPort.setPort(new Port(dstInterface.getPort()));
761
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200762 for (Interface srcInterface : interfaces.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800763
Jonathan Hart45107222013-10-22 17:35:04 -0700764 if (dstInterface.equals(srcInterface)){
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200765 continue;
766 }
pingping-linba5c52f2014-02-11 16:52:01 -0800767
768 // Create flowPath FlowId
769 //FlowId returnByRefFlowId = new FlowId(flowManagerService.getNextFlowEntryId());
770 //flowPath.setFlowId(returnByRefFlowId);
771 flowPath.setFlowId(new FlowId());
772
773 // Create the DataPath object: srcSwitchPort
774 SwitchPort srcPort = new SwitchPort();
775 srcPort.setDpid(new Dpid(srcInterface.getDpid()));
776 srcPort.setPort(new Port(srcInterface.getPort()));
777
778 DataPath dataPath = new DataPath();
779 dataPath.setSrcPort(srcPort);
780 dataPath.setDstPort(dstPort);
781 flowPath.setDataPath(dataPath);
782
783 // Create the Flow Path Match condition(s)
784 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
785 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPv4);
786 flowEntryMatch.enableDstMac(dstMacAddress);
787 flowPath.setFlowEntryMatch(flowEntryMatch);
788
789 // NOTE: No need to add ACTION_OUTPUT. It is implied when creating
790 // Shortest Path Flow, and is always the last action for the Flow Entries
791 log.debug("FlowPath of MAC based forwarding: {}", flowPath.toString());
792 if (flowManagerService.addFlow(flowPath) == null) {
793 log.error("Failed to set up MAC based forwarding path to {}, {}",
794 path.getDstIpAddress().getHostAddress(),dstMacAddress);
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200795 }
796 else {
pingping-linba5c52f2014-02-11 16:52:01 -0800797 log.debug("Successfully set up MAC based forwarding path to {}, {}",
798 path.getDstIpAddress().getHostAddress(),dstMacAddress);
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200799 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200800 }
801 }
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200802
pingping-linba5c52f2014-02-11 16:52:01 -0800803 /**
804 * Pre-actively install all BGP traffic paths from BGP host attachment point
805 * in SDN network to all the virtual gateways to BGP peers in other networks
806 */
807 private void setupBgpPaths(){
808
809 for (BgpPeer bgpPeer : bgpPeers.values()){
810
811 FlowPath flowPath = new FlowPath();
812 flowPath.setInstallerId(new CallerId("SDNIP"));
813
814 // Set flowPath FlowPathType and FlowPathUserState
815 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
816 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
817
818 // Install flow paths between BGPd and its peers
819 // There is no need to set the FlowPathFlags
820 flowPath.setFlowPathFlags(new FlowPathFlags(0));
821
822 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
823
824 // set flowPath FlowId
825 //FlowId returnByRefFlowId = new FlowId(flowManagerService.getNextFlowEntryId());
826 //flowPath.setFlowId(returnByRefFlowId);
827
828
829 // Create the Flow Path Match condition(s)
830 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
831 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPv4);
832
833 // Match both source address and dest address
834 IPv4Net dstIPv4Net= new IPv4Net(bgpPeer.getIpAddress().getHostAddress()+"/32");
835 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
836
837 IPv4Net srcIPv4Net= new IPv4Net(peerInterface.getIpAddress().getHostAddress()+"/32");
838 flowEntryMatch.enableSrcIPv4Net(srcIPv4Net);
839
840 // Match TCP protocol
841 flowEntryMatch.enableIpProto(IPv4.PROTOCOL_TCP);
842
843 // Match destination TCP port
844 flowEntryMatch.enableDstTcpUdpPort(BGP_PORT);
845 flowPath.setFlowEntryMatch(flowEntryMatch);
846
847 /**
848 * Create the DataPath: BGP -> BGP peer
849 */
850 // Flow path for src-TCP-port
851 DataPath dataPath = new DataPath();
852
853 SwitchPort srcPort = new SwitchPort();
854 srcPort.setDpid(bgpdAttachmentPoint.dpid());
855 srcPort.setPort(bgpdAttachmentPoint.port());
856 dataPath.setSrcPort(srcPort);
857
858 SwitchPort dstPort = new SwitchPort();
859 dstPort.setDpid(new Dpid(peerInterface.getDpid()));
860 dstPort.setPort(new Port(peerInterface.getSwitchPort().port()));
861 dataPath.setDstPort(dstPort);
862
863 flowPath.setDataPath(dataPath);
864
865 if (flowManagerService.addFlow(flowPath) == null) {
866 log.error("Failed to set up path BGP -> peer {}"+"; dst-TCP-port:179",
867 bgpPeer.getIpAddress().getHostAddress());
868 }
869 else {
870 log.debug("Successfully set up path BGP -> peer {}"+"; dst-TCP-port:179",
871 bgpPeer.getIpAddress().getHostAddress());
872 }
873
874 // Disable dst-TCP-port, and set src-TCP-port
875 flowEntryMatch.disableDstTcpUdpPort();
876 flowEntryMatch.enableSrcTcpUdpPort(BGP_PORT);
877 flowPath.setFlowEntryMatch(flowEntryMatch);
878
879 // Create a new FlowId
880 //FlowId returnByRefFlowId2 = new FlowId(flowManagerService.getNextFlowEntryId());
881 //flowPath.setFlowId(returnByRefFlowId2);
882 flowPath.setFlowId(new FlowId());
883
884 if (flowManagerService.addFlow(flowPath) == null) {
885 log.error("Failed to set up path BGP -> Peer {}" + "; src-TCP-port:179",
886 bgpPeer.getIpAddress().getHostAddress());
887 }
888 else {
889 log.debug("Successfully set up path BGP -> Peer {}" + "; src-TCP-port:179",
890 bgpPeer.getIpAddress().getHostAddress());
891 }
892
893 /**
894 * Create the DataPath: BGP <-BGP peer
895 */
896 // Reversed BGP flow path for src-TCP-port
897 //FlowId returnByRefFlowId3 = new FlowId(flowManagerService.getNextFlowEntryId());
898 //flowPath.setFlowId(returnByRefFlowId3);
899 flowPath.setFlowId(new FlowId());
900
901 DataPath reverse_dataPath = new DataPath();
902
903 SwitchPort reverse_dstPort = new SwitchPort();
904 reverse_dstPort.setDpid(bgpdAttachmentPoint.dpid());
905 reverse_dstPort.setPort(bgpdAttachmentPoint.port());
906 reverse_dataPath.setDstPort(reverse_dstPort);
907
908 SwitchPort reverse_srcPort = new SwitchPort();
909 reverse_srcPort.setDpid(new Dpid(peerInterface.getDpid()));
910 reverse_srcPort.setPort(new Port(peerInterface.getSwitchPort().port()));
911 reverse_dataPath.setSrcPort(reverse_srcPort);
912 flowPath.setDataPath(reverse_dataPath);
913
914 // reverse the dst IP and src IP addresses
915 flowEntryMatch.enableDstIPv4Net(srcIPv4Net);
916 flowEntryMatch.enableSrcIPv4Net(dstIPv4Net);
917 flowPath.setFlowEntryMatch(flowEntryMatch);
918
919 log.debug("Reversed BGP FlowPath: {}", flowPath.toString());
920
921 if (flowManagerService.addFlow(flowPath) == null) {
922
923 log.error("Failed to set up path BGP <- Peer {}" + "; src-TCP-port:179",
924 bgpPeer.getIpAddress().getHostAddress());
925 }
926 else {
927 log.debug("Successfully set up path BGP <- Peer {}" + "; src-TCP-port:179",
928 bgpPeer.getIpAddress().getHostAddress());
929 }
930
931 // Reversed BGP flow path for dst-TCP-port
932 //FlowId returnByRefFlowId4 = new FlowId(flowManagerService.getNextFlowEntryId());
933 //flowPath.setFlowId(returnByRefFlowId4);
934 flowPath.setFlowId(new FlowId());
935
936 // Disable src-TCP-port, and set the dst-TCP-port
937 flowEntryMatch.disableSrcTcpUdpPort();
938 flowEntryMatch.enableDstTcpUdpPort(BGP_PORT);
939 flowPath.setFlowEntryMatch(flowEntryMatch);
940
941 log.debug("Reversed BGP FlowPath: {}", flowPath.toString());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700942
pingping-linba5c52f2014-02-11 16:52:01 -0800943 if (flowManagerService.addFlow(flowPath) == null) {
944 log.error("Failed to setting up path BGP <- Peer {}" + "; dst-TCP-port:179",
945 bgpPeer.getIpAddress().getHostAddress());
946 }
947 else {
948 log.debug("Successfully setting up path BGP <- Peer {}" + "; dst-TCP-port:179",
949 bgpPeer.getIpAddress().getHostAddress());
950 }
951
952 /**
953 * ICMP paths between BGPd and its peers
954 */
955 //match ICMP protocol BGP <- Peer
956 //FlowId returnByRefFlowId5 = new FlowId(flowManagerService.getNextFlowEntryId());
957 //flowPath.setFlowId(returnByRefFlowId5);
958 flowPath.setFlowId(new FlowId());
959
960 flowEntryMatch.enableIpProto(IPv4.PROTOCOL_ICMP);
961 flowEntryMatch.disableSrcTcpUdpPort();
962 flowEntryMatch.disableDstTcpUdpPort();
963
964 flowPath.setFlowEntryMatch(flowEntryMatch);
965
966 flowPath.setDataPath(reverse_dataPath);
967
968 log.debug("Reversed ICMP FlowPath: {}", flowPath.toString());
969
970 if (flowManagerService.addFlow(flowPath) == null) {
971
972 log.error("Failed to set up ICMP path BGP <- Peer {}",
973 bgpPeer.getIpAddress().getHostAddress());
974 }
975 else {
976 log.debug("Successfully set up ICMP path BGP <- Peer {}",
977 bgpPeer.getIpAddress().getHostAddress());
978 }
979
980 //match ICMP protocol BGP -> Peer
981 //FlowId returnByRefFlowId6 = new FlowId(flowManagerService.getNextFlowEntryId());
982 //flowPath.setFlowId(returnByRefFlowId6);
983 flowPath.setFlowId(new FlowId());
984
985 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
986 flowEntryMatch.enableSrcIPv4Net(srcIPv4Net);
987 flowPath.setFlowEntryMatch(flowEntryMatch);
988
989 flowPath.setDataPath(dataPath);
990
991 log.debug("ICMP flowPath: {}", flowPath.toString());
992
993
994 if (flowManagerService.addFlow(flowPath) == null) {
995
996 log.error("Failed to set up ICMP path BGP -> Peer {}",
997 bgpPeer.getIpAddress().getHostAddress());
998 }
999 else {
1000 log.debug("Successfully set up ICMP path BGP -> Peer {}",
1001 bgpPeer.getIpAddress().getHostAddress());
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001002 }
1003 }
1004 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001005
Jonathan Hart4dfc3652013-08-02 20:22:36 +12001006 @Override
Jonathan Hartabad6a52013-09-30 18:17:21 +13001007 public void arpResponse(InetAddress ipAddress, MACAddress macAddress) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001008 log.debug("Received ARP response: {} => {}",
Jonathan Hartabad6a52013-09-30 18:17:21 +13001009 ipAddress.getHostAddress(), macAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001010
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001011 /*
1012 * We synchronize on this to prevent changes to the ptree while we're pushing
1013 * flows to the switches. If the ptree changes, the ptree and switches
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001014 * could get out of sync.
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001015 */
1016 synchronized (this) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001017 Path path = pathsWaitingOnArp.remove(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001018
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001019 if (path != null) {
Jonathan Hart309889c2013-08-13 23:26:24 +12001020 log.debug("Pushing path to {} at {} on {}", new Object[] {
Jonathan Hartabad6a52013-09-30 18:17:21 +13001021 path.getDstIpAddress().getHostAddress(), macAddress,
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001022 path.getDstInterface().getSwitchPort()});
1023 //These paths should always be to BGP peers. Paths to non-peers are
1024 //handled once the first prefix is ready to push
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001025 if (pushedPaths.containsKey(path.getDstIpAddress())) {
Jonathan Hart309889c2013-08-13 23:26:24 +12001026 //A path already got pushed to this endpoint while we were waiting
1027 //for ARP. We'll copy over the permanent attribute if it is set on this path.
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001028 if (path.isPermanent()) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001029 pushedPaths.get(path.getDstIpAddress()).setPermanent();
Jonathan Hart309889c2013-08-13 23:26:24 +12001030 }
1031 }
1032 else {
Jonathan Hartabad6a52013-09-30 18:17:21 +13001033 calculateAndPushPath(path, macAddress);
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001034 pushedPaths.put(path.getDstIpAddress(), path);
Jonathan Hart309889c2013-08-13 23:26:24 +12001035 }
1036 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001037
Jonathan Hart309889c2013-08-13 23:26:24 +12001038 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001039
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001040 for (RibUpdate update : prefixesToPush) {
1041 //These will always be adds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001042
1043 RibEntry rib = ptree.lookup(update.getPrefix());
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001044 if (rib != null && rib.equals(update.getRibEntry())) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001045 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001046 rib.getNextHop().getHostAddress());
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001047 //We only push prefix flows if the prefix is still in the ptree
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001048 //and the next hop is the same as our update. The prefix could
1049 //have been removed while we were waiting for the ARP, or the
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001050 //next hop could have changed.
Jonathan Hart309889c2013-08-13 23:26:24 +12001051 _processRibAdd(update);
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001052 } else {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001053 log.debug("Received ARP response, but {},{} is no longer in ptree",
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001054 update.getPrefix(), update.getRibEntry());
1055 }
1056 }
Jonathan Hart0ee0f022013-08-03 22:21:54 +12001057 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +12001058 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001059
pingping-linba5c52f2014-02-11 16:52:01 -08001060 //TODO wait the priority module of the flow Manager
Jonathan Hartc82051c2013-08-24 15:12:20 +12001061 private void setupArpFlows() {
1062 OFMatch match = new OFMatch();
1063 match.setDataLayerType(Ethernet.TYPE_ARP);
1064 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001065
Jonathan Hartc82051c2013-08-24 15:12:20 +12001066 OFFlowMod fm = new OFFlowMod();
1067 fm.setMatch(match);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001068
Jonathan Hartc82051c2013-08-24 15:12:20 +12001069 OFActionOutput action = new OFActionOutput();
1070 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1071 action.setMaxLength((short)0xffff);
1072 List<OFAction> actions = new ArrayList<OFAction>(1);
1073 actions.add(action);
1074 fm.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001075
Jonathan Hartc82051c2013-08-24 15:12:20 +12001076 fm.setIdleTimeout((short)0)
pingping-linba5c52f2014-02-11 16:52:01 -08001077 .setHardTimeout((short)0)
1078 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1079 .setCookie(0)
1080 .setCommand(OFFlowMod.OFPFC_ADD)
1081 .setPriority(ARP_PRIORITY)
Jonathan Hartc82051c2013-08-24 15:12:20 +12001082 .setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001083
Jonathan Hartc82051c2013-08-24 15:12:20 +12001084 for (String strdpid : switches){
Jonathan Hart1912afc2013-10-11 12:02:44 +13001085 flowCache.write(HexString.toLong(strdpid), fm);
Jonathan Hartc82051c2013-08-24 15:12:20 +12001086 }
1087 }
pingping-linba5c52f2014-02-11 16:52:01 -08001088 //TODO need update, waiting for the priority feature from flow Manager
Jonathan Hartf886fa12013-09-18 14:46:29 +12001089 private void setupDefaultDropFlows() {
1090 OFFlowMod fm = new OFFlowMod();
1091 fm.setMatch(new OFMatch());
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001092 fm.setActions(new ArrayList<OFAction>()); //No action means drop
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001093
Jonathan Hartf886fa12013-09-18 14:46:29 +12001094 fm.setIdleTimeout((short)0)
pingping-linba5c52f2014-02-11 16:52:01 -08001095 .setHardTimeout((short)0)
1096 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1097 .setCookie(0)
1098 .setCommand(OFFlowMod.OFPFC_ADD)
1099 .setPriority((short)0)
Jonathan Hartf886fa12013-09-18 14:46:29 +12001100 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001101
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001102 OFFlowMod fmLLDP;
1103 OFFlowMod fmBDDP;
1104 try {
pingping-linba5c52f2014-02-11 16:52:01 -08001105 fmLLDP = fm.clone();
1106 fmBDDP = fm.clone();
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001107 } catch (CloneNotSupportedException e1) {
1108 log.error("Error cloning flow mod", e1);
1109 return;
1110 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001111
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001112 OFMatch matchLLDP = new OFMatch();
Stacey Sheldon44433002014-01-21 00:43:09 -05001113 matchLLDP.setDataLayerType((short)0x88cc);
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001114 matchLLDP.setWildcards(matchLLDP.getWildcards() & ~ OFMatch.OFPFW_DL_TYPE);
1115 fmLLDP.setMatch(matchLLDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001116
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001117 OFMatch matchBDDP = new OFMatch();
Stacey Sheldon44433002014-01-21 00:43:09 -05001118 matchBDDP.setDataLayerType((short)0x8942);
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001119 matchBDDP.setWildcards(matchBDDP.getWildcards() & ~ OFMatch.OFPFW_DL_TYPE);
1120 fmBDDP.setMatch(matchBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001121
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001122 OFActionOutput action = new OFActionOutput();
1123 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1124 action.setMaxLength((short)0xffff);
1125 List<OFAction> actions = new ArrayList<OFAction>(1);
1126 actions.add(action);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001127
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001128 fmLLDP.setActions(actions);
1129 fmBDDP.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001130
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001131 fmLLDP.setPriority(ARP_PRIORITY);
1132 fmLLDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1133 fmBDDP.setPriority(ARP_PRIORITY);
1134 fmBDDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001135
1136 List<OFFlowMod> flowModList = new ArrayList<OFFlowMod>(3);
Jonathan Hart1912afc2013-10-11 12:02:44 +13001137 flowModList.add(fm);
1138 flowModList.add(fmLLDP);
1139 flowModList.add(fmBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001140
Jonathan Hartf886fa12013-09-18 14:46:29 +12001141 for (String strdpid : switches){
Jonathan Hart1912afc2013-10-11 12:02:44 +13001142 flowCache.write(HexString.toLong(strdpid), flowModList);
Jonathan Hartf886fa12013-09-18 14:46:29 +12001143 }
1144 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001145
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001146 private void beginRouting(){
1147 log.debug("Topology is now ready, beginning routing function");
Pavlin Radoslavov15954d42013-10-19 15:29:04 -07001148 topology = topologyNetService.newDatabaseTopology();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001149
pingping-linba5c52f2014-02-11 16:52:01 -08001150 // Wait Pavlin's API. We need the following functions.
1151 /*setupArpFlows();
1152 setupDefaultDropFlows();*/
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001153
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001154 setupBgpPaths();
Jonathan Hart98957bf2013-07-01 14:49:24 +12001155 setupFullMesh();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001156
Jonathan Harte7694532013-09-12 12:34:46 +12001157 //Suppress link discovery on external-facing router ports
1158 for (Interface intf : interfaces.values()) {
1159 linkDiscoveryService.AddToSuppressLLDPs(intf.getDpid(), intf.getPort());
1160 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001161
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001162 bgpUpdatesExecutor.execute(new Runnable() {
1163 @Override
1164 public void run() {
1165 doUpdatesThread();
1166 }
1167 });
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001168 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001169
pingping-linba5c52f2014-02-11 16:52:01 -08001170 // Before inserting the paths for BGP traffic, we should check
1171 // whether all the switches in the configure file are discovered by onos.
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001172 private void checkSwitchesConnected(){
1173 for (String dpid : switches){
pingping-linba5c52f2014-02-11 16:52:01 -08001174 Iterator<ISwitchObject> activeSwitches = topoSwitchService.
1175 getActiveSwitches().iterator();
1176 while(activeSwitches.hasNext())
1177 {
1178 ISwitchObject switchObject = activeSwitches.next();
1179 if (switchObject.getDPID().equals(dpid)) {
1180 break;
1181 }
1182 if(activeSwitches.hasNext() == false) {
1183 log.debug("Not all switches are here yet");
1184 return;
1185 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001186 }
1187 }
1188 switchesConnected = true;
1189 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001190
Jonathan Hartc824ad02013-07-03 15:58:45 +12001191 //Actually we only need to go half way round to verify full mesh connectivity
1192 //(n^2)/2
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001193 private void checkTopologyReady(){
Jonathan Hartc824ad02013-07-03 15:58:45 +12001194 for (Interface dstInterface : interfaces.values()) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001195 for (Interface srcInterface : interfaces.values()) {
Jonathan Hart45107222013-10-22 17:35:04 -07001196 if (dstInterface.equals(srcInterface)) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001197 continue;
1198 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001199
Pavlin Radoslavov15954d42013-10-19 15:29:04 -07001200 DataPath shortestPath = topologyNetService.getDatabaseShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +12001201 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001202
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001203 if (shortestPath == null){
1204 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +12001205 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001206 return;
1207 }
1208 }
1209 }
1210 topologyReady = true;
1211 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001212
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001213 private void checkStatus(){
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001214 if (!switchesConnected){
1215 checkSwitchesConnected();
1216 }
1217 boolean oldTopologyReadyStatus = topologyReady;
1218 if (switchesConnected && !topologyReady){
1219 checkTopologyReady();
1220 }
1221 if (!oldTopologyReadyStatus && topologyReady){
1222 beginRouting();
1223 }
1224 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001225
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001226 private void doUpdatesThread() {
1227 boolean interrupted = false;
1228 try {
1229 while (true) {
1230 try {
1231 RibUpdate update = ribUpdates.take();
1232 switch (update.getOperation()){
1233 case UPDATE:
Jonathan Harte4c98692013-10-18 17:40:03 -07001234 if (validateUpdate(update)) {
1235 processRibAdd(update);
1236 }
1237 else {
1238 log.debug("Rib UPDATE out of order: {} via {}",
1239 update.getPrefix(), update.getRibEntry().getNextHop());
1240 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001241 break;
1242 case DELETE:
Jonathan Harte4c98692013-10-18 17:40:03 -07001243 if (validateUpdate(update)) {
1244 processRibDelete(update);
1245 }
1246 else {
1247 log.debug("Rib DELETE out of order: {} via {}",
1248 update.getPrefix(), update.getRibEntry().getNextHop());
1249 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001250 break;
1251 }
1252 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001253 log.debug("Interrupted while taking from updates queue", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001254 interrupted = true;
Jonathan Hart309889c2013-08-13 23:26:24 +12001255 } catch (Exception e) {
1256 log.debug("exception", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001257 }
1258 }
1259 } finally {
1260 if (interrupted) {
1261 Thread.currentThread().interrupt();
1262 }
1263 }
1264 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001265
Jonathan Harte4c98692013-10-18 17:40:03 -07001266 private boolean validateUpdate(RibUpdate update) {
1267 RibEntry newEntry = update.getRibEntry();
1268 RibEntry oldEntry = ptree.lookup(update.getPrefix());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001269
Jonathan Harte4c98692013-10-18 17:40:03 -07001270 //If there is no existing entry we must assume this is the most recent
1271 //update. However this might not always be the case as we might have a
1272 //POST then DELETE reordering.
1273 //if (oldEntry == null || !newEntry.getNextHop().equals(oldEntry.getNextHop())) {
1274 if (oldEntry == null) {
1275 return true;
1276 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001277
Jonathan Harte4c98692013-10-18 17:40:03 -07001278 // This handles the case where routes are gathered in the initial
1279 // request because they don't have sequence number info
1280 if (newEntry.getSysUpTime() == -1 && newEntry.getSequenceNum() == -1) {
1281 return true;
1282 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001283
Jonathan Harte4c98692013-10-18 17:40:03 -07001284 if (newEntry.getSysUpTime() > oldEntry.getSysUpTime()) {
1285 return true;
1286 }
1287 else if (newEntry.getSysUpTime() == oldEntry.getSysUpTime()) {
1288 if (newEntry.getSequenceNum() > oldEntry.getSequenceNum()) {
1289 return true;
1290 }
1291 else {
1292 return false;
1293 }
1294 }
1295 else {
1296 return false;
1297 }
1298 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001299
1300 @Override
Jonathan Hart64c0b202013-08-20 15:45:07 +12001301 public void topologyChanged() {
1302 if (topologyReady) {
1303 return;
1304 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001305
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001306 boolean refreshNeeded = false;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -07001307 for (LDUpdate ldu : topologyService.getLastLinkUpdates()){
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001308 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1309 //We don't need to recalculate anything for just link updates
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001310 //They happen very frequently
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001311 refreshNeeded = true;
1312 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001313
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001314 log.debug("Topo change {}", ldu.getOperation());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001315
Jonathan Hart98957bf2013-07-01 14:49:24 +12001316 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1317 synchronized (linkUpdates) {
1318 linkUpdates.add(ldu);
1319 }
1320 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001321 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001322
Jonathan Hart64c0b202013-08-20 15:45:07 +12001323 if (refreshNeeded && !topologyReady){
Jonathan Hart98957bf2013-07-01 14:49:24 +12001324 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
pingping-lina2cbfad2013-03-07 08:39:21 +08001325 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001326 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001327
1328 @Override
1329 public void addedSwitch(IOFSwitch sw) {
1330 if (!topologyReady) {
1331 sw.clearAllFlowMods();
1332 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001333
Jonathan Hart1912afc2013-10-11 12:02:44 +13001334 flowCache.switchConnected(sw);
Jonathan Hart64c0b202013-08-20 15:45:07 +12001335 }
1336
1337 @Override
Jonathan Hart08ee8522013-09-22 17:34:43 +12001338 public void removedSwitch(IOFSwitch sw) {}
Jonathan Hart64c0b202013-08-20 15:45:07 +12001339
1340 @Override
Jonathan Hart08ee8522013-09-22 17:34:43 +12001341 public void switchPortChanged(Long switchId) {}
Jonathan Hart64c0b202013-08-20 15:45:07 +12001342
1343 @Override
1344 public String getName() {
Jonathan Hart08ee8522013-09-22 17:34:43 +12001345 return "BgpRoute";
1346 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001347
Jonathan Hart08ee8522013-09-22 17:34:43 +12001348 /*
Jonathan Harta8887642013-10-28 13:46:54 -07001349 * IConfigInfoService methods
Jonathan Hart08ee8522013-09-22 17:34:43 +12001350 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001351
Jonathan Hart08ee8522013-09-22 17:34:43 +12001352 @Override
1353 public boolean isInterfaceAddress(InetAddress address) {
1354 Interface intf = interfacePtrie.match(new Prefix(address.getAddress(), 32));
1355 return (intf != null && intf.getIpAddress().equals(address));
1356 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001357
Jonathan Hart08ee8522013-09-22 17:34:43 +12001358 @Override
1359 public boolean inConnectedNetwork(InetAddress address) {
1360 Interface intf = interfacePtrie.match(new Prefix(address.getAddress(), 32));
1361 return (intf != null && !intf.getIpAddress().equals(address));
1362 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001363
Jonathan Hart08ee8522013-09-22 17:34:43 +12001364 @Override
1365 public boolean fromExternalNetwork(long inDpid, short inPort) {
1366 for (Interface intf : interfaces.values()) {
1367 if (intf.getDpid() == inDpid && intf.getPort() == inPort) {
1368 return true;
1369 }
1370 }
1371 return false;
1372 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001373
Jonathan Hart08ee8522013-09-22 17:34:43 +12001374 @Override
1375 public Interface getOutgoingInterface(InetAddress dstIpAddress) {
1376 return interfacePtrie.match(new Prefix(dstIpAddress.getAddress(), 32));
1377 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001378
Jonathan Hart08ee8522013-09-22 17:34:43 +12001379 @Override
1380 public boolean hasLayer3Configuration() {
1381 return !interfaces.isEmpty();
1382 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001383
Jonathan Hart08ee8522013-09-22 17:34:43 +12001384 @Override
1385 public MACAddress getRouterMacAddress() {
1386 return bgpdMacAddress;
Jonathan Hart64c0b202013-08-20 15:45:07 +12001387 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001388
Jonathan Harta8887642013-10-28 13:46:54 -07001389 @Override
1390 public short getVlan() {
1391 return vlan;
1392 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001393}