blob: 64e2447121f3775c454723b2010e0c8954203e20 [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;
HIGUCHI Yutaa56fbde2013-06-17 14:26:05 -070045import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery;
46import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscovery.LDUpdate;
Jonathan Harte7694532013-09-12 12:34:46 +120047import net.onrc.onos.ofcontroller.linkdiscovery.ILinkDiscoveryService;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120048import net.onrc.onos.ofcontroller.proxyarp.IArpRequester;
pingping-linba5c52f2014-02-11 16:52:01 -080049import net.onrc.onos.ofcontroller.proxyarp.IProxyArpService;
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -070050import net.onrc.onos.ofcontroller.topology.ITopologyNetService;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070051import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavove1b37bc2013-10-16 03:57:06 -070052import net.onrc.onos.ofcontroller.topology.TopologyManager;
pingping-linba5c52f2014-02-11 16:52:01 -080053import net.onrc.onos.ofcontroller.util.CallerId;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070054import net.onrc.onos.ofcontroller.util.DataPath;
Jonathan Hart832a7cb2013-06-24 11:25:35 +120055import net.onrc.onos.ofcontroller.util.Dpid;
pingping-linba5c52f2014-02-11 16:52:01 -080056import net.onrc.onos.ofcontroller.util.FlowEntryAction;
57import net.onrc.onos.ofcontroller.util.FlowEntryActions;
58import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
59import net.onrc.onos.ofcontroller.util.FlowId;
60import net.onrc.onos.ofcontroller.util.FlowPath;
61import net.onrc.onos.ofcontroller.util.FlowPathFlags;
62import net.onrc.onos.ofcontroller.util.FlowPathType;
63import net.onrc.onos.ofcontroller.util.FlowPathUserState;
64import net.onrc.onos.ofcontroller.util.IPv4Net;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070065import net.onrc.onos.ofcontroller.util.Port;
66import net.onrc.onos.ofcontroller.util.SwitchPort;
pingping-line2a09ca2013-03-23 09:33:58 +080067import net.sf.json.JSONArray;
68import net.sf.json.JSONObject;
69import net.sf.json.JSONSerializer;
pingping-lina2cbfad2013-03-07 08:39:21 +080070
Jonathan Hartd1f23252013-06-13 15:17:05 +120071import org.codehaus.jackson.JsonParseException;
72import org.codehaus.jackson.map.JsonMappingException;
73import org.codehaus.jackson.map.ObjectMapper;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070074import org.openflow.protocol.OFFlowMod;
75import org.openflow.protocol.OFMatch;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070076import org.openflow.protocol.OFPacketOut;
Jonathan Hart9575cb62013-07-05 13:43:49 +120077import org.openflow.protocol.OFPort;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070078import org.openflow.protocol.action.OFAction;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -070079import org.openflow.protocol.action.OFActionOutput;
Jonathan Hart1236a9b2013-06-18 22:10:05 +120080import org.openflow.util.HexString;
pingping-lina2cbfad2013-03-07 08:39:21 +080081import org.slf4j.Logger;
82import org.slf4j.LoggerFactory;
83
Jonathan Hart4dfc3652013-08-02 20:22:36 +120084import com.google.common.collect.HashMultimap;
Jonathan Hart0ee0f022013-08-03 22:21:54 +120085import com.google.common.collect.Multimap;
Jonathan Hart4dfc3652013-08-02 20:22:36 +120086import com.google.common.collect.Multimaps;
87import com.google.common.collect.SetMultimap;
Jonathan Hart309889c2013-08-13 23:26:24 +120088import com.google.common.net.InetAddresses;
Jonathan Hart8b9349e2013-07-26 15:55:28 +120089import com.google.common.util.concurrent.ThreadFactoryBuilder;
90
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070091public class BgpRoute implements IFloodlightModule, IBgpRouteService,
Jonathan Hart64c0b202013-08-20 15:45:07 +120092 ITopologyListener, IArpRequester,
Jonathan Hart7804bea2014-01-07 10:50:52 -080093 IOFSwitchListener, IConfigInfoService {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -070094
Yuta HIGUCHI6ac8d182013-10-22 15:24:56 -070095 private final static Logger log = LoggerFactory.getLogger(BgpRoute.class);
pingping-lina2cbfad2013-03-07 08:39:21 +080096
Jonathan Hartf247ee72013-10-18 18:57:28 -070097 private IFloodlightProviderService floodlightProvider;
Jonathan Hart3a326122013-10-21 11:51:13 -070098 private ITopologyService topologyService;
Jonathan Hartf247ee72013-10-18 18:57:28 -070099 private ITopologyNetService topologyNetService;
100 private ILinkDiscoveryService linkDiscoveryService;
101 private IRestApiService restApi;
pingping-linba5c52f2014-02-11 16:52:01 -0800102 private IProxyArpService proxyArp;
pingping-linba5c52f2014-02-11 16:52:01 -0800103 private IDeviceStorage deviceStorage;
104 private ITopoSwitchService topoSwitchService;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700105
Jonathan Hartf247ee72013-10-18 18:57:28 -0700106 private IPatriciaTrie<RibEntry> ptree;
107 private IPatriciaTrie<Interface> interfacePtrie;
108 private BlockingQueue<RibUpdate> ribUpdates;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700109
Jonathan Hartf247ee72013-10-18 18:57:28 -0700110 private String bgpdRestIp;
111 private String routerId;
112 private String configFilename = "config.json";
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700113
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700114 //We need to identify our flows somehow. But like it says in LearningSwitch.java,
115 //the controller/OS should hand out cookie IDs to prevent conflicts.
Jonathan Hartf247ee72013-10-18 18:57:28 -0700116 private final long APP_COOKIE = 0xa0000000000000L;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700117 //Cookie for flows that do L2 forwarding within SDN domain to egress routers
Jonathan Hartf247ee72013-10-18 18:57:28 -0700118 private final long L2_FWD_COOKIE = APP_COOKIE + 1;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700119 //Cookie for flows in ingress switches that rewrite the MAC address
Jonathan Hartf247ee72013-10-18 18:57:28 -0700120 private final long MAC_RW_COOKIE = APP_COOKIE + 2;
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200121 //Cookie for flows that setup BGP paths
Jonathan Hartf247ee72013-10-18 18:57:28 -0700122 private final long BGP_COOKIE = APP_COOKIE + 3;
Jonathan Hart50a8d1e2013-06-06 16:00:47 +1200123 //Forwarding uses priority 0, and the mac rewrite entries in ingress switches
124 //need to be higher priority than this otherwise the rewrite may not get done
Jonathan Hartf247ee72013-10-18 18:57:28 -0700125 private final short SDNIP_PRIORITY = 10;
126 private final short ARP_PRIORITY = 20;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700127
Jonathan Hartf247ee72013-10-18 18:57:28 -0700128 private final short BGP_PORT = 179;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700129
Jonathan Hartf247ee72013-10-18 18:57:28 -0700130 private final int TOPO_DETECTION_WAIT = 2; //seconds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700131
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200132 //Configuration stuff
Jonathan Hartf247ee72013-10-18 18:57:28 -0700133 private List<String> switches;
134 private Map<String, Interface> interfaces;
135 private Map<InetAddress, BgpPeer> bgpPeers;
136 private SwitchPort bgpdAttachmentPoint;
137 private MACAddress bgpdMacAddress;
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700138 private short vlan;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700139
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200140 //True when all switches have connected
Jonathan Hartf247ee72013-10-18 18:57:28 -0700141 private volatile boolean switchesConnected = false;
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200142 //True when we have a full mesh of shortest paths between gateways
Jonathan Hartf247ee72013-10-18 18:57:28 -0700143 private volatile boolean topologyReady = false;
Jonathan Hart98957bf2013-07-01 14:49:24 +1200144
Jonathan Hartf247ee72013-10-18 18:57:28 -0700145 private ArrayList<LDUpdate> linkUpdates;
146 private SingletonTask topologyChangeDetectorTask;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700147
Jonathan Hartf247ee72013-10-18 18:57:28 -0700148 private SetMultimap<InetAddress, RibUpdate> prefixesWaitingOnArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700149
Jonathan Hartf247ee72013-10-18 18:57:28 -0700150 private Map<InetAddress, Path> pathsWaitingOnArp;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700151
Jonathan Hartf247ee72013-10-18 18:57:28 -0700152 private ExecutorService bgpUpdatesExecutor;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700153
Jonathan Hartf247ee72013-10-18 18:57:28 -0700154 private Map<InetAddress, Path> pushedPaths;
155 private Map<Prefix, Path> prefixToPath;
pingping-linba5c52f2014-02-11 16:52:01 -0800156// private Multimap<Prefix, PushedFlowMod> pushedFlows;
157 private Multimap<Prefix, FlowId> pushedFlowIds;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700158
Jonathan Hart1912afc2013-10-11 12:02:44 +1300159 private FlowCache flowCache;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700160
Jonathan Hart3a326122013-10-21 11:51:13 -0700161 private volatile Topology topology = null;
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700162
Jonathan Hartf247ee72013-10-18 18:57:28 -0700163 private class TopologyChangeDetector implements Runnable {
Jonathan Hart98957bf2013-07-01 14:49:24 +1200164 @Override
165 public void run() {
166 log.debug("Running topology change detection task");
167 synchronized (linkUpdates) {
Jonathan Hartc824ad02013-07-03 15:58:45 +1200168 //This is the model the REST API uses to retrieve network graph info
Jonathan Hart98957bf2013-07-01 14:49:24 +1200169 ITopoLinkService topoLinkService = new TopoLinkServiceImpl();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700170
Jonathan Hart98957bf2013-07-01 14:49:24 +1200171 List<Link> activeLinks = topoLinkService.getActiveLinks();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700172
Jonathan Hart98957bf2013-07-01 14:49:24 +1200173 Iterator<LDUpdate> it = linkUpdates.iterator();
174 while (it.hasNext()){
175 LDUpdate ldu = it.next();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700176 Link l = new Link(ldu.getSrc(), ldu.getSrcPort(),
Jonathan Hart98957bf2013-07-01 14:49:24 +1200177 ldu.getDst(), ldu.getDstPort());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700178
Jonathan Hart98957bf2013-07-01 14:49:24 +1200179 if (activeLinks.contains(l)){
Jonathan Hart98957bf2013-07-01 14:49:24 +1200180 it.remove();
181 }
182 }
183 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700184
Jonathan Hart64c0b202013-08-20 15:45:07 +1200185 if (!topologyReady) {
186 if (linkUpdates.isEmpty()){
187 //All updates have been seen in network map.
188 //We can check if topology is ready
189 log.debug("No known changes outstanding. Checking topology now");
190 checkStatus();
191 }
192 else {
193 //We know of some link updates that haven't propagated to the database yet
194 log.debug("Some changes not found in network map - {} links missing", linkUpdates.size());
195 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
196 }
Jonathan Hart98957bf2013-07-01 14:49:24 +1200197 }
198 }
199 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700200
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700201 private void readConfiguration(String configFilename){
202 File gatewaysFile = new File(configFilename);
Jonathan Hartd1f23252013-06-13 15:17:05 +1200203 ObjectMapper mapper = new ObjectMapper();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700204
Jonathan Hartd1f23252013-06-13 15:17:05 +1200205 try {
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200206 Configuration config = mapper.readValue(gatewaysFile, Configuration.class);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700207
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200208 switches = config.getSwitches();
Jonathan Hart9575cb62013-07-05 13:43:49 +1200209 interfaces = new HashMap<String, Interface>();
210 for (Interface intf : config.getInterfaces()){
211 interfaces.put(intf.getName(), intf);
212 }
Jonathan Hartc824ad02013-07-03 15:58:45 +1200213 bgpPeers = new HashMap<InetAddress, BgpPeer>();
214 for (BgpPeer peer : config.getPeers()){
215 bgpPeers.put(peer.getIpAddress(), peer);
216 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700217
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200218 bgpdAttachmentPoint = new SwitchPort(
219 new Dpid(config.getBgpdAttachmentDpid()),
220 new Port(config.getBgpdAttachmentPort()));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700221
Jonathan Hart2f790d22013-08-15 14:01:24 +1200222 bgpdMacAddress = config.getBgpdMacAddress();
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700223 vlan = config.getVlan();
Jonathan Hartd1f23252013-06-13 15:17:05 +1200224 } catch (JsonParseException e) {
225 log.error("Error in JSON file", e);
226 System.exit(1);
227 } catch (JsonMappingException e) {
228 log.error("Error in JSON file", e);
229 System.exit(1);
230 } catch (IOException e) {
231 log.error("Error reading JSON file", e);
232 System.exit(1);
233 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700234
Jonathan Hartabf10222013-08-13 10:19:34 +1200235 //Populate the interface Patricia Trie
236 for (Interface intf : interfaces.values()) {
237 Prefix prefix = new Prefix(intf.getIpAddress().getAddress(), intf.getPrefixLength());
238 interfacePtrie.put(prefix, intf);
239 }
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700240 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700241
pingping-lina2cbfad2013-03-07 08:39:21 +0800242 @Override
243 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700244 Collection<Class<? extends IFloodlightService>> l
Jonathan Hart61ba9372013-05-19 20:10:29 -0700245 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800246 l.add(IBgpRouteService.class);
Jonathan Harta8887642013-10-28 13:46:54 -0700247 l.add(IConfigInfoService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800248 return l;
249 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700250
pingping-lina2cbfad2013-03-07 08:39:21 +0800251 @Override
252 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700253 Map<Class<? extends IFloodlightService>, IFloodlightService> m
Jonathan Hart61ba9372013-05-19 20:10:29 -0700254 = new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
pingping-line2a09ca2013-03-23 09:33:58 +0800255 m.put(IBgpRouteService.class, this);
Jonathan Harta8887642013-10-28 13:46:54 -0700256 m.put(IConfigInfoService.class, this);
pingping-lina2cbfad2013-03-07 08:39:21 +0800257 return m;
258 }
259
pingping-lina2cbfad2013-03-07 08:39:21 +0800260 @Override
261 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700262 Collection<Class<? extends IFloodlightService>> l
Jonathan Hart61ba9372013-05-19 20:10:29 -0700263 = new ArrayList<Class<? extends IFloodlightService>>();
pingping-lina2cbfad2013-03-07 08:39:21 +0800264 l.add(IFloodlightProviderService.class);
265 l.add(ITopologyService.class);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700266 l.add(IRestApiService.class);
pingping-lina2cbfad2013-03-07 08:39:21 +0800267 return l;
268 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700269
pingping-lina2cbfad2013-03-07 08:39:21 +0800270 @Override
271 public void init(FloodlightModuleContext context)
272 throws FloodlightModuleException {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700273
Jonathan Hart29b972d2013-08-12 23:43:51 +1200274 ptree = new PatriciaTrie<RibEntry>(32);
Jonathan Hartabf10222013-08-13 10:19:34 +1200275 interfacePtrie = new PatriciaTrie<Interface>(32);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700276
pingping-linba5c52f2014-02-11 16:52:01 -0800277 ribUpdates = new LinkedBlockingQueue<RibUpdate>();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700278
pingping-lina2cbfad2013-03-07 08:39:21 +0800279 // Register floodlight provider and REST handler.
280 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700281 topologyService = context.getServiceImpl(ITopologyService.class);
Jonathan Harte7694532013-09-12 12:34:46 +1200282 linkDiscoveryService = context.getServiceImpl(ILinkDiscoveryService.class);
Jonathan Hartc7ca35d2013-06-25 20:54:25 +1200283 restApi = context.getServiceImpl(IRestApiService.class);
pingping-linba5c52f2014-02-11 16:52:01 -0800284 proxyArp = context.getServiceImpl(IProxyArpService.class);
285
286 deviceStorage = new DeviceStorageImpl();
287 deviceStorage.init("", "");
288
Jonathan Hart98957bf2013-07-01 14:49:24 +1200289 linkUpdates = new ArrayList<LDUpdate>();
290 ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
291 topologyChangeDetectorTask = new SingletonTask(executor, new TopologyChangeDetector());
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700292
yoshif7424e42013-11-25 22:07:40 -0800293 topologyNetService = new TopologyManager(context);
pingping-linba5c52f2014-02-11 16:52:01 -0800294 topoSwitchService = new TopoSwitchServiceImpl();
295
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200296 pathsWaitingOnArp = new HashMap<InetAddress, Path>();
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200297 prefixesWaitingOnArp = Multimaps.synchronizedSetMultimap(
298 HashMultimap.<InetAddress, RibUpdate>create());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700299
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200300 pushedPaths = new HashMap<InetAddress, Path>();
301 prefixToPath = new HashMap<Prefix, Path>();
pingping-linba5c52f2014-02-11 16:52:01 -0800302// pushedFlows = HashMultimap.<Prefix, PushedFlowMod>create();
303 pushedFlowIds = HashMultimap.<Prefix, FlowId>create();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700304
Jonathan Hart1912afc2013-10-11 12:02:44 +1300305 flowCache = new FlowCache(floodlightProvider);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700306
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200307 bgpUpdatesExecutor = Executors.newSingleThreadExecutor(
308 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700309
Jonathan Hart61ba9372013-05-19 20:10:29 -0700310 //Read in config values
311 bgpdRestIp = context.getConfigParams(this).get("BgpdRestIp");
312 if (bgpdRestIp == null){
313 log.error("BgpdRestIp property not found in config file");
314 System.exit(1);
315 }
316 else {
317 log.info("BgpdRestIp set to {}", bgpdRestIp);
318 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700319
Jonathan Hart61ba9372013-05-19 20:10:29 -0700320 routerId = context.getConfigParams(this).get("RouterId");
321 if (routerId == null){
322 log.error("RouterId property not found in config file");
323 System.exit(1);
324 }
325 else {
326 log.info("RouterId set to {}", routerId);
327 }
pingping-linba5c52f2014-02-11 16:52:01 -0800328
Jonathan Hart9575cb62013-07-05 13:43:49 +1200329 String configFilenameParameter = context.getConfigParams(this).get("configfile");
330 if (configFilenameParameter != null){
331 configFilename = configFilenameParameter;
332 }
333 log.debug("Config file set to {}", configFilename);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700334
Jonathan Hart1cf9de02013-10-21 17:42:29 -0700335 readConfiguration(configFilename);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200336 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700337
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200338 @Override
339 public void startUp(FloodlightModuleContext context) {
340 restApi.addRestletRoutable(new BgpRouteWebRoutable());
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700341 topologyService.addListener(this);
Jonathan Hart64c0b202013-08-20 15:45:07 +1200342 floodlightProvider.addOFSwitchListener(this);
pingping-linba5c52f2014-02-11 16:52:01 -0800343
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200344 //Retrieve the RIB from BGPd during startup
345 retrieveRib();
pingping-lina2cbfad2013-03-07 08:39:21 +0800346 }
347
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700348 @Override
Jonathan Hart29b972d2013-08-12 23:43:51 +1200349 public IPatriciaTrie<RibEntry> getPtree() {
pingping-lina2cbfad2013-03-07 08:39:21 +0800350 return ptree;
351 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700352
353 @Override
Jonathan Hart61ba9372013-05-19 20:10:29 -0700354 public void clearPtree() {
Jonathan Hart29b972d2013-08-12 23:43:51 +1200355 ptree = new PatriciaTrie<RibEntry>(32);
pingping-line2a09ca2013-03-23 09:33:58 +0800356 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700357
358 @Override
pingping-line2a09ca2013-03-23 09:33:58 +0800359 public String getBGPdRestIp() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700360 return bgpdRestIp;
pingping-line2a09ca2013-03-23 09:33:58 +0800361 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700362
363 @Override
pingping-line2a09ca2013-03-23 09:33:58 +0800364 public String getRouterId() {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700365 return routerId;
pingping-line2a09ca2013-03-23 09:33:58 +0800366 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700367
Jonathan Hart61ba9372013-05-19 20:10:29 -0700368 private void retrieveRib(){
369 String url = "http://" + bgpdRestIp + "/wm/bgp/" + routerId;
370 String response = RestClient.get(url);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700371
Jonathan Hart61ba9372013-05-19 20:10:29 -0700372 if (response.equals("")){
373 return;
374 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700375
Jonathan Hart61ba9372013-05-19 20:10:29 -0700376 response = response.replaceAll("\"", "'");
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700377 JSONObject jsonObj = (JSONObject) JSONSerializer.toJSON(response);
Jonathan Hart61ba9372013-05-19 20:10:29 -0700378 JSONArray rib_json_array = jsonObj.getJSONArray("rib");
379 String router_id = jsonObj.getString("router-id");
380
381 int size = rib_json_array.size();
382
383 log.info("Retrived RIB of {} entries from BGPd", size);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700384
Jonathan Hart61ba9372013-05-19 20:10:29 -0700385 for (int j = 0; j < size; j++) {
386 JSONObject second_json_object = rib_json_array.getJSONObject(j);
387 String prefix = second_json_object.getString("prefix");
388 String nexthop = second_json_object.getString("nexthop");
389
390 //insert each rib entry into the local rib;
391 String[] substring = prefix.split("/");
392 String prefix1 = substring[0];
393 String mask1 = substring[1];
394
395 Prefix p;
396 try {
397 p = new Prefix(prefix1, Integer.valueOf(mask1));
398 } catch (NumberFormatException e) {
399 log.warn("Wrong mask format in RIB JSON: {}", mask1);
400 continue;
Jonathan Hart32e18222013-08-07 22:05:42 +1200401 } catch (IllegalArgumentException e1) {
Jonathan Hart61ba9372013-05-19 20:10:29 -0700402 log.warn("Wrong prefix format in RIB JSON: {}", prefix1);
403 continue;
404 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700405
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200406 RibEntry rib = new RibEntry(router_id, nexthop);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700407
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200408 try {
409 ribUpdates.put(new RibUpdate(Operation.UPDATE, p, rib));
410 } catch (InterruptedException e) {
411 log.debug("Interrupted while pushing onto update queue");
412 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700413 }
Jonathan Hart61ba9372013-05-19 20:10:29 -0700414 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700415
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200416 @Override
417 public void newRibUpdate(RibUpdate update) {
Jonathan Hart9ea31212013-08-12 21:40:34 +1200418 try {
419 ribUpdates.put(update);
420 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200421 log.debug("Interrupted while putting on ribUpdates queue", e);
422 Thread.currentThread().interrupt();
Jonathan Hart9ea31212013-08-12 21:40:34 +1200423 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200424 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700425
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200426 public synchronized void processRibAdd(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200427 Prefix prefix = update.getPrefix();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700428
Jonathan Hart9ea31212013-08-12 21:40:34 +1200429 log.debug("Processing prefix add {}", prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700430
Jonathan Hartb39a67d2013-08-10 23:59:50 +1200431 RibEntry rib = ptree.put(prefix, update.getRibEntry());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700432
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200433 if (rib != null && !rib.equals(update.getRibEntry())) {
Jonathan Hart2f740782013-08-04 00:49:21 +1200434 //There was an existing nexthop for this prefix. This update supersedes that,
435 //so we need to remove the old flows for this prefix from the switches
Jonathan Hart309889c2013-08-13 23:26:24 +1200436 _processDeletePrefix(prefix, rib);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200437 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700438
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200439 if (update.getRibEntry().getNextHop().equals(
440 InetAddresses.forString("0.0.0.0"))) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200441 //Route originated by SDN domain
442 //We don't handle these at the moment
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700443 log.debug("Own route {} to {}", prefix,
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200444 update.getRibEntry().getNextHop().getHostAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200445 return;
446 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700447
Jonathan Hart309889c2013-08-13 23:26:24 +1200448 _processRibAdd(update);
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200449 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700450
Jonathan Hart309889c2013-08-13 23:26:24 +1200451 private void _processRibAdd(RibUpdate update) {
452 Prefix prefix = update.getPrefix();
453 RibEntry rib = update.getRibEntry();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700454
Jonathan Hart309889c2013-08-13 23:26:24 +1200455 InetAddress dstIpAddress = rib.getNextHop();
pingping-linba5c52f2014-02-11 16:52:01 -0800456 MACAddress nextHopMacAddress;
457
458 // See if we know the MAC address of the next hop
459 // TODO if we do not treat the next hop as a device in the future, we need to update this
460 IDeviceObject nextHopDevice =
461 deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(dstIpAddress));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700462
pingping-linba5c52f2014-02-11 16:52:01 -0800463 if (nextHopDevice == null){
464 log.debug("NextHopDevice for IP: {} is null", dstIpAddress);
465 prefixesWaitingOnArp.put(dstIpAddress,
466 new RibUpdate(Operation.UPDATE, prefix, rib));
467 proxyArp.sendArpRequest(dstIpAddress, this, true);
468 return;
469
470 }
471 nextHopMacAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700472
pingping-linba5c52f2014-02-11 16:52:01 -0800473 // Find the attachment point (egress interface) of the next hop
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200474 Interface egressInterface = null;
Jonathan Hart309889c2013-08-13 23:26:24 +1200475 if (bgpPeers.containsKey(dstIpAddress)) {
476 //Route to a peer
477 log.debug("Route to peer {}", dstIpAddress);
478 BgpPeer peer = bgpPeers.get(dstIpAddress);
479 egressInterface = interfaces.get(peer.getInterfaceName());
Jonathan Hart309889c2013-08-13 23:26:24 +1200480 }
481 else {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200482 //Route to non-peer
Jonathan Hart309889c2013-08-13 23:26:24 +1200483 log.debug("Route to non-peer {}", dstIpAddress);
484 egressInterface = interfacePtrie.match(
485 new Prefix(dstIpAddress.getAddress(), 32));
486 if (egressInterface == null) {
487 log.warn("No outgoing interface found for {}", dstIpAddress.getHostAddress());
488 return;
489 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200490 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700491
Jonathan Hart309889c2013-08-13 23:26:24 +1200492 if (nextHopMacAddress == null) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700493 prefixesWaitingOnArp.put(dstIpAddress,
Jonathan Hart309889c2013-08-13 23:26:24 +1200494 new RibUpdate(Operation.UPDATE, prefix, rib));
495 proxyArp.sendArpRequest(dstIpAddress, this, true);
496 return;
497 }
498 else {
499 if (!bgpPeers.containsKey(dstIpAddress)) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200500 //If the prefix is for a non-peer we need to ensure there's a path,
501 //and push one if there isn't.
502 Path path = pushedPaths.get(dstIpAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200503 if (path == null) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200504 path = new Path(egressInterface, dstIpAddress);
Jonathan Hartabad6a52013-09-30 18:17:21 +1300505 calculateAndPushPath(path, nextHopMacAddress);
Jonathan Hart309889c2013-08-13 23:26:24 +1200506 pushedPaths.put(dstIpAddress, path);
507 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700508
Jonathan Hart309889c2013-08-13 23:26:24 +1200509 path.incrementUsers();
510 prefixToPath.put(prefix, path);
511 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700512
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200513 //For all prefixes we need to add the first-hop mac-rewriting flows
Jonathan Hart309889c2013-08-13 23:26:24 +1200514 addPrefixFlows(prefix, egressInterface, nextHopMacAddress);
515 }
516 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700517
pingping-linba5c52f2014-02-11 16:52:01 -0800518 /**
519 * Add a flow to match dst-IP prefix and rewrite MAC for one IP prefix
520 * to all other border switches
521 */
522 private void addPrefixFlows(Prefix prefix, Interface egressInterface,
523 MACAddress nextHopMacAddress) {
Jonathan Harte4c98692013-10-18 17:40:03 -0700524 log.debug("Adding flows for prefix {}, next hop mac {}",
Jonathan Hartabad6a52013-09-30 18:17:21 +1300525 prefix, nextHopMacAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700526
pingping-linba5c52f2014-02-11 16:52:01 -0800527 FlowPath flowPath = new FlowPath();
528 flowPath.setInstallerId(new CallerId("SDNIP"));
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700529
pingping-linba5c52f2014-02-11 16:52:01 -0800530 // Set flowPath FlowPathType and FlowPathUserState
531 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
532 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
533
534 // Insert dst-ip prefix based forwarding and MAC rewrite flow entry
535 // only to the first-host switches
536 FlowPathFlags flowPathFlags = new FlowPathFlags();
537 flowPathFlags.setFlags(FlowPathFlags.KEEP_ONLY_FIRST_HOP_ENTRY);
538 flowPath.setFlowPathFlags(flowPathFlags);
539
540 // Create the DataPath object: dstSwitchPort
541 SwitchPort dstPort = new SwitchPort();
542 dstPort.setDpid(new Dpid(egressInterface.getDpid()));
543 dstPort.setPort(new Port(egressInterface.getPort()));
544
545 // We only need one flow mod per switch, so pick one interface on each switch
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200546 Map<Long, Interface> srcInterfaces = new HashMap<Long, Interface>();
547 for (Interface intf : interfaces.values()) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700548 if (!srcInterfaces.containsKey(intf.getDpid())
Jonathan Hart45107222013-10-22 17:35:04 -0700549 && !intf.equals(egressInterface)) {
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200550 srcInterfaces.put(intf.getDpid(), intf);
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200551 }
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200552 }
Jonathan Hartd5f2e952013-09-13 16:31:23 +1200553 for (Interface srcInterface : srcInterfaces.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800554
555 if (egressInterface.equals(srcInterface)){
556 continue;
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200557 }
pingping-linba5c52f2014-02-11 16:52:01 -0800558
559 // Create flowPath FlowId
pingping-linba5c52f2014-02-11 16:52:01 -0800560 flowPath.setFlowId(new FlowId());
561
562 // Create DataPath object: srcSwitchPort
563 SwitchPort srcPort = new SwitchPort();
564 srcPort.setDpid(new Dpid(srcInterface.getDpid()));
565 srcPort.setPort(new Port(srcInterface.getPort()));
566
567 DataPath dataPath = new DataPath();
568 dataPath.setSrcPort(srcPort);
569 dataPath.setDstPort(dstPort);
570 flowPath.setDataPath(dataPath);
571
572 // Create flow path matching condition(s): IPv4 Prefix
573 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
574 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPv4);
575 IPv4Net dstIPv4Net= new IPv4Net(prefix.toString());
576 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
577 flowPath.setFlowEntryMatch(flowEntryMatch);
Jonathan Hart1912afc2013-10-11 12:02:44 +1300578
579 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800580 * Create the Flow Entry Action(s): dst-MAC rewrite action
Jonathan Hart1912afc2013-10-11 12:02:44 +1300581 */
pingping-linba5c52f2014-02-11 16:52:01 -0800582 FlowEntryActions flowEntryActions = new FlowEntryActions();
583 FlowEntryAction flowEntryAction1 = new FlowEntryAction();
584 flowEntryAction1.setActionSetEthernetDstAddr(nextHopMacAddress);
585 // flowEntryAction1.actionSetEthernetDstAddr(nextHopMacAddress);
586 flowEntryActions.addAction(flowEntryAction1);
587 flowPath.setFlowEntryActions(flowEntryActions);
588
589 // Flow Path installation, only to first hop switches
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700590 // TODO: Add the flow by using the new Path Intent framework
591 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800592 if (flowManagerService.addFlow(flowPath) == null) {
593 log.error("Failed to install flow path to the first hop for " +
594 "prefix: {}, nextHopMacAddress: {}", prefix.getAddress(),
595 nextHopMacAddress);
596 }
597 else {
598 log.debug("Successfully installed flow path to the first hop " +
599 "for prefix: {}, nextHopMacAddress: {}", prefix.getAddress(),
600 nextHopMacAddress);
601
602 pushedFlowIds.put(prefix, flowPath.flowId());
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200603 }
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700604 */
Jonathan Hart309889c2013-08-13 23:26:24 +1200605 }
606 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700607
Jonathan Hart0a46fe42013-08-10 17:08:47 +1200608 public synchronized void processRibDelete(RibUpdate update) {
Jonathan Hart8b9349e2013-07-26 15:55:28 +1200609 Prefix prefix = update.getPrefix();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700610
Jonathan Hartd7e158d2013-08-07 23:04:48 +1200611 if (ptree.remove(prefix, update.getRibEntry())) {
612 /*
613 * Only delete flows if an entry was actually removed from the trie.
614 * If no entry was removed, the <prefix, nexthop> wasn't there so
615 * it's probably already been removed and we don't need to do anything
616 */
Jonathan Hart309889c2013-08-13 23:26:24 +1200617 _processDeletePrefix(prefix, update.getRibEntry());
Jonathan Hart309889c2013-08-13 23:26:24 +1200618 }
619 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700620
Jonathan Hart309889c2013-08-13 23:26:24 +1200621 private void _processDeletePrefix(Prefix prefix, RibEntry ribEntry) {
622 deletePrefixFlows(prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700623
Jonathan Hart309889c2013-08-13 23:26:24 +1200624 log.debug("Deleting {} to {}", prefix, ribEntry.getNextHop());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700625
Jonathan Hart309889c2013-08-13 23:26:24 +1200626 if (!bgpPeers.containsKey(ribEntry.getNextHop())) {
627 log.debug("Getting path for route with non-peer nexthop");
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200628 Path path = prefixToPath.remove(prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700629
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200630 if (path != null) {
631 //path could be null if we added to the Ptree but didn't push
632 //flows yet because we were waiting to resolve ARP
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700633
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200634 path.decrementUsers();
Jonathan Hartd992f1a2013-09-13 13:46:44 +1200635 if (path.getUsers() <= 0 && !path.isPermanent()) {
636 deletePath(path);
637 pushedPaths.remove(path.getDstIpAddress());
638 }
Jonathan Hart309889c2013-08-13 23:26:24 +1200639 }
640 }
641 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700642
pingping-linba5c52f2014-02-11 16:52:01 -0800643 // TODO have not tested this module
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200644 private void deletePrefixFlows(Prefix prefix) {
645 log.debug("Deleting flows for prefix {}", prefix);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700646
pingping-linba5c52f2014-02-11 16:52:01 -0800647 Collection<FlowId> flowIds = pushedFlowIds.removeAll(prefix);
648 for (FlowId flowId : flowIds) {
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700649 // TODO: Delete the flow by using the new Path Intent framework
650 /*
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 }
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700665 */
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200666 }
667 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700668
pingping-linba5c52f2014-02-11 16:52:01 -0800669 // TODO need to record the path and then delete here
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200670 private void deletePath(Path path) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700671 log.debug("Deleting flows for path to {}",
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200672 path.getDstIpAddress().getHostAddress());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700673
pingping-linba5c52f2014-02-11 16:52:01 -0800674 // TODO need update
675 /*for (PushedFlowMod pfm : path.getFlowMods()) {
Jonathan Hart5b803bc2013-09-23 14:46:11 +1200676 if (log.isTraceEnabled()) {
677 log.trace("Pushing a DELETE flow mod to {}, dst MAC {}",
678 new Object[] {HexString.toHexString(pfm.getDpid()),
679 HexString.toHexString(pfm.getFlowMod().getMatch().getDataLayerDestination())
680 });
681 }
pingping-linba5c52f2014-02-11 16:52:01 -0800682
Jonathan Hart309889c2013-08-13 23:26:24 +1200683 sendDeleteFlowMod(pfm.getFlowMod(), pfm.getDpid());
pingping-linba5c52f2014-02-11 16:52:01 -0800684 }*/
Jonathan Hart309889c2013-08-13 23:26:24 +1200685 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700686
687
Jonathan Hart0ee0f022013-08-03 22:21:54 +1200688 //TODO test next-hop changes
Jonathan Hart2f740782013-08-04 00:49:21 +1200689 //TODO check delete/add synchronization
pingping-linba5c52f2014-02-11 16:52:01 -0800690
691 /**
692 * On startup, we need to calculate a full mesh of paths between all gateway
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700693 * switches
694 */
Jonathan Hart1236a9b2013-06-18 22:10:05 +1200695 private void setupFullMesh(){
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700696 //For each border router, calculate and install a path from every other
697 //border switch to said border router. However, don't install the entry
698 //in to the first hop switch, as we need to install an entry to rewrite
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700699 //for each prefix received. This will be done later when prefixes have
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700700 //actually been received.
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700701
Jonathan Hartc824ad02013-07-03 15:58:45 +1200702 for (BgpPeer peer : bgpPeers.values()) {
703 Interface peerInterface = interfaces.get(peer.getInterfaceName());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700704
Jonathan Hart309889c2013-08-13 23:26:24 +1200705 //We know there's not already a Path here pushed, because this is
706 //called before all other routing
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200707 Path path = new Path(peerInterface, peer.getIpAddress());
Jonathan Hart309889c2013-08-13 23:26:24 +1200708 path.setPermanent();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700709
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200710 //See if we know the MAC address of the peer. If not we can't
711 //do anything until we learn it
pingping-linba5c52f2014-02-11 16:52:01 -0800712 MACAddress macAddress;
713 IDeviceObject nextHopDevice =
714 deviceStorage.getDeviceByIP(InetAddresses.coerceToInteger(peer.getIpAddress()));
715
716 if(nextHopDevice == null){
717 log.debug("There is no DeviceObject for {}", peer.getIpAddress().getHostAddress());
718 //Put in the pending paths list first
719 pathsWaitingOnArp.put(peer.getIpAddress(), path);
720 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
721 continue;
722 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700723
pingping-linba5c52f2014-02-11 16:52:01 -0800724 macAddress = MACAddress.valueOf(nextHopDevice.getMACAddress());
725
Jonathan Hartabad6a52013-09-30 18:17:21 +1300726 if (macAddress == null) {
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200727 log.debug("Don't know MAC for {}", peer.getIpAddress().getHostAddress());
728 //Put in the pending paths list first
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200729 pathsWaitingOnArp.put(peer.getIpAddress(), path);
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200730 proxyArp.sendArpRequest(peer.getIpAddress(), this, true);
731 continue;
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700732 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700733
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200734 //If we know the MAC, lets go ahead and push the paths to this peer
Jonathan Hartabad6a52013-09-30 18:17:21 +1300735 calculateAndPushPath(path, macAddress);
Jonathan Harte7e1c6e2013-06-04 20:50:23 -0700736 }
737 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700738
Jonathan Harta23ffdb2013-08-14 14:36:54 +1200739 private void calculateAndPushPath(Path path, MACAddress dstMacAddress) {
Jonathan Hart309889c2013-08-13 23:26:24 +1200740 Interface dstInterface = path.getDstInterface();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -0700741
Jonathan Hartfb1ebc52013-08-17 16:25:51 +1200742 log.debug("Setting up path to {}, {}", path.getDstIpAddress().getHostAddress(),
743 dstMacAddress);
pingping-linba5c52f2014-02-11 16:52:01 -0800744
745 FlowPath flowPath = new FlowPath();
746
747 flowPath.setInstallerId(new CallerId("SDNIP"));
748
749 // Set flowPath FlowPathType and FlowPathUserState
750 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
751 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
752
753 // Insert the dest-mac based forwarding flow entry to the non-first-hop switches
754 FlowPathFlags flowPathFlags = new FlowPathFlags();
755 flowPathFlags.setFlags(FlowPathFlags.DISCARD_FIRST_HOP_ENTRY);
756 flowPath.setFlowPathFlags(flowPathFlags);
757
758 // Create the DataPath object: dstSwitchPort
759 SwitchPort dstPort = new SwitchPort();
760 dstPort.setDpid(new Dpid(dstInterface.getDpid()));
761 dstPort.setPort(new Port(dstInterface.getPort()));
762
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200763 for (Interface srcInterface : interfaces.values()) {
pingping-linba5c52f2014-02-11 16:52:01 -0800764
Jonathan Hart45107222013-10-22 17:35:04 -0700765 if (dstInterface.equals(srcInterface)){
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200766 continue;
767 }
pingping-linba5c52f2014-02-11 16:52:01 -0800768
769 // Create flowPath FlowId
pingping-linba5c52f2014-02-11 16:52:01 -0800770 flowPath.setFlowId(new FlowId());
771
772 // Create the DataPath object: srcSwitchPort
773 SwitchPort srcPort = new SwitchPort();
774 srcPort.setDpid(new Dpid(srcInterface.getDpid()));
775 srcPort.setPort(new Port(srcInterface.getPort()));
776
777 DataPath dataPath = new DataPath();
778 dataPath.setSrcPort(srcPort);
779 dataPath.setDstPort(dstPort);
780 flowPath.setDataPath(dataPath);
781
782 // Create the Flow Path Match condition(s)
783 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
784 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPv4);
785 flowEntryMatch.enableDstMac(dstMacAddress);
786 flowPath.setFlowEntryMatch(flowEntryMatch);
787
788 // NOTE: No need to add ACTION_OUTPUT. It is implied when creating
789 // Shortest Path Flow, and is always the last action for the Flow Entries
790 log.debug("FlowPath of MAC based forwarding: {}", flowPath.toString());
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700791 // TODO: Add the flow by using the new Path Intent framework
792 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800793 if (flowManagerService.addFlow(flowPath) == null) {
794 log.error("Failed to set up MAC based forwarding path to {}, {}",
795 path.getDstIpAddress().getHostAddress(),dstMacAddress);
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200796 }
797 else {
pingping-linba5c52f2014-02-11 16:52:01 -0800798 log.debug("Successfully set up MAC based forwarding path to {}, {}",
799 path.getDstIpAddress().getHostAddress(),dstMacAddress);
Jonathan Hartdefa44d2013-08-15 19:51:13 +1200800 }
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700801 */
Jonathan Hart4dfc3652013-08-02 20:22:36 +1200802 }
803 }
Jonathan Hart832a7cb2013-06-24 11:25:35 +1200804
pingping-linba5c52f2014-02-11 16:52:01 -0800805 /**
806 * Pre-actively install all BGP traffic paths from BGP host attachment point
807 * in SDN network to all the virtual gateways to BGP peers in other networks
808 */
809 private void setupBgpPaths(){
810
811 for (BgpPeer bgpPeer : bgpPeers.values()){
812
813 FlowPath flowPath = new FlowPath();
814 flowPath.setInstallerId(new CallerId("SDNIP"));
815
816 // Set flowPath FlowPathType and FlowPathUserState
817 flowPath.setFlowPathType(FlowPathType.FP_TYPE_SHORTEST_PATH);
818 flowPath.setFlowPathUserState(FlowPathUserState.FP_USER_ADD);
819
820 // Install flow paths between BGPd and its peers
821 // There is no need to set the FlowPathFlags
822 flowPath.setFlowPathFlags(new FlowPathFlags(0));
823
824 Interface peerInterface = interfaces.get(bgpPeer.getInterfaceName());
825
pingping-linba5c52f2014-02-11 16:52:01 -0800826 // Create the Flow Path Match condition(s)
827 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
828 flowEntryMatch.enableEthernetFrameType(Ethernet.TYPE_IPv4);
829
830 // Match both source address and dest address
831 IPv4Net dstIPv4Net= new IPv4Net(bgpPeer.getIpAddress().getHostAddress()+"/32");
832 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
833
834 IPv4Net srcIPv4Net= new IPv4Net(peerInterface.getIpAddress().getHostAddress()+"/32");
835 flowEntryMatch.enableSrcIPv4Net(srcIPv4Net);
836
837 // Match TCP protocol
838 flowEntryMatch.enableIpProto(IPv4.PROTOCOL_TCP);
839
840 // Match destination TCP port
841 flowEntryMatch.enableDstTcpUdpPort(BGP_PORT);
842 flowPath.setFlowEntryMatch(flowEntryMatch);
843
844 /**
845 * Create the DataPath: BGP -> BGP peer
846 */
847 // Flow path for src-TCP-port
848 DataPath dataPath = new DataPath();
849
850 SwitchPort srcPort = new SwitchPort();
851 srcPort.setDpid(bgpdAttachmentPoint.dpid());
852 srcPort.setPort(bgpdAttachmentPoint.port());
853 dataPath.setSrcPort(srcPort);
854
855 SwitchPort dstPort = new SwitchPort();
856 dstPort.setDpid(new Dpid(peerInterface.getDpid()));
857 dstPort.setPort(new Port(peerInterface.getSwitchPort().port()));
858 dataPath.setDstPort(dstPort);
859
860 flowPath.setDataPath(dataPath);
861
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700862 // TODO: Add the flow by using the new Path Intent framework
863 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800864 if (flowManagerService.addFlow(flowPath) == null) {
865 log.error("Failed to set up path BGP -> peer {}"+"; dst-TCP-port:179",
866 bgpPeer.getIpAddress().getHostAddress());
867 }
868 else {
869 log.debug("Successfully set up path BGP -> peer {}"+"; dst-TCP-port:179",
870 bgpPeer.getIpAddress().getHostAddress());
871 }
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700872 */
pingping-linba5c52f2014-02-11 16:52:01 -0800873
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
pingping-linba5c52f2014-02-11 16:52:01 -0800880 flowPath.setFlowId(new FlowId());
881
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700882 // TODO: Add the flow by using the new Path Intent framework
883 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800884 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 }
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700892 */
pingping-linba5c52f2014-02-11 16:52:01 -0800893
894 /**
895 * Create the DataPath: BGP <-BGP peer
896 */
897 // Reversed BGP flow path for src-TCP-port
pingping-linba5c52f2014-02-11 16:52:01 -0800898 flowPath.setFlowId(new FlowId());
899
900 DataPath reverse_dataPath = new DataPath();
901
902 SwitchPort reverse_dstPort = new SwitchPort();
903 reverse_dstPort.setDpid(bgpdAttachmentPoint.dpid());
904 reverse_dstPort.setPort(bgpdAttachmentPoint.port());
905 reverse_dataPath.setDstPort(reverse_dstPort);
906
907 SwitchPort reverse_srcPort = new SwitchPort();
908 reverse_srcPort.setDpid(new Dpid(peerInterface.getDpid()));
909 reverse_srcPort.setPort(new Port(peerInterface.getSwitchPort().port()));
910 reverse_dataPath.setSrcPort(reverse_srcPort);
911 flowPath.setDataPath(reverse_dataPath);
912
913 // reverse the dst IP and src IP addresses
914 flowEntryMatch.enableDstIPv4Net(srcIPv4Net);
915 flowEntryMatch.enableSrcIPv4Net(dstIPv4Net);
916 flowPath.setFlowEntryMatch(flowEntryMatch);
917
918 log.debug("Reversed BGP FlowPath: {}", flowPath.toString());
919
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700920 // TODO: Add the flow by using the new Path Intent framework
921 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800922 if (flowManagerService.addFlow(flowPath) == null) {
923
924 log.error("Failed to set up path BGP <- Peer {}" + "; src-TCP-port:179",
925 bgpPeer.getIpAddress().getHostAddress());
926 }
927 else {
928 log.debug("Successfully set up path BGP <- Peer {}" + "; src-TCP-port:179",
929 bgpPeer.getIpAddress().getHostAddress());
930 }
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700931 */
pingping-linba5c52f2014-02-11 16:52:01 -0800932
933 // Reversed BGP flow path for dst-TCP-port
pingping-linba5c52f2014-02-11 16:52:01 -0800934 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
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700943 // TODO: Add the flow by using the new Path Intent framework
944 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800945 if (flowManagerService.addFlow(flowPath) == null) {
946 log.error("Failed to setting up path BGP <- Peer {}" + "; dst-TCP-port:179",
947 bgpPeer.getIpAddress().getHostAddress());
948 }
949 else {
950 log.debug("Successfully setting up path BGP <- Peer {}" + "; dst-TCP-port:179",
951 bgpPeer.getIpAddress().getHostAddress());
952 }
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700953 */
pingping-linba5c52f2014-02-11 16:52:01 -0800954
955 /**
956 * ICMP paths between BGPd and its peers
957 */
958 //match ICMP protocol BGP <- Peer
pingping-linba5c52f2014-02-11 16:52:01 -0800959 flowPath.setFlowId(new FlowId());
960
961 flowEntryMatch.enableIpProto(IPv4.PROTOCOL_ICMP);
962 flowEntryMatch.disableSrcTcpUdpPort();
963 flowEntryMatch.disableDstTcpUdpPort();
964
965 flowPath.setFlowEntryMatch(flowEntryMatch);
966
967 flowPath.setDataPath(reverse_dataPath);
968
969 log.debug("Reversed ICMP FlowPath: {}", flowPath.toString());
970
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700971 // TODO: Add the flow by using the new Path Intent framework
972 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800973 if (flowManagerService.addFlow(flowPath) == null) {
974
975 log.error("Failed to set up ICMP path BGP <- Peer {}",
976 bgpPeer.getIpAddress().getHostAddress());
977 }
978 else {
979 log.debug("Successfully set up ICMP path BGP <- Peer {}",
980 bgpPeer.getIpAddress().getHostAddress());
981 }
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700982 */
pingping-linba5c52f2014-02-11 16:52:01 -0800983
984 //match ICMP protocol BGP -> Peer
pingping-linba5c52f2014-02-11 16:52:01 -0800985 flowPath.setFlowId(new FlowId());
986
987 flowEntryMatch.enableDstIPv4Net(dstIPv4Net);
988 flowEntryMatch.enableSrcIPv4Net(srcIPv4Net);
989 flowPath.setFlowEntryMatch(flowEntryMatch);
990
991 flowPath.setDataPath(dataPath);
992
993 log.debug("ICMP flowPath: {}", flowPath.toString());
994
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -0700995 // TODO: Add the flow by using the new Path Intent framework
996 /*
pingping-linba5c52f2014-02-11 16:52:01 -0800997 if (flowManagerService.addFlow(flowPath) == null) {
998
999 log.error("Failed to set up ICMP path BGP -> Peer {}",
1000 bgpPeer.getIpAddress().getHostAddress());
1001 }
1002 else {
1003 log.debug("Successfully set up ICMP path BGP -> Peer {}",
1004 bgpPeer.getIpAddress().getHostAddress());
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001005 }
Pavlin Radoslavov39f0f2e2014-03-20 12:04:57 -07001006 */
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001007 }
1008 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001009
Jonathan Hart4dfc3652013-08-02 20:22:36 +12001010 @Override
Jonathan Hartabad6a52013-09-30 18:17:21 +13001011 public void arpResponse(InetAddress ipAddress, MACAddress macAddress) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001012 log.debug("Received ARP response: {} => {}",
Jonathan Hartabad6a52013-09-30 18:17:21 +13001013 ipAddress.getHostAddress(), macAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001014
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001015 /*
1016 * We synchronize on this to prevent changes to the ptree while we're pushing
1017 * flows to the switches. If the ptree changes, the ptree and switches
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001018 * could get out of sync.
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001019 */
1020 synchronized (this) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001021 Path path = pathsWaitingOnArp.remove(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001022
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001023 if (path != null) {
Jonathan Hart309889c2013-08-13 23:26:24 +12001024 log.debug("Pushing path to {} at {} on {}", new Object[] {
Jonathan Hartabad6a52013-09-30 18:17:21 +13001025 path.getDstIpAddress().getHostAddress(), macAddress,
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001026 path.getDstInterface().getSwitchPort()});
1027 //These paths should always be to BGP peers. Paths to non-peers are
1028 //handled once the first prefix is ready to push
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001029 if (pushedPaths.containsKey(path.getDstIpAddress())) {
Jonathan Hart309889c2013-08-13 23:26:24 +12001030 //A path already got pushed to this endpoint while we were waiting
1031 //for ARP. We'll copy over the permanent attribute if it is set on this path.
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001032 if (path.isPermanent()) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001033 pushedPaths.get(path.getDstIpAddress()).setPermanent();
Jonathan Hart309889c2013-08-13 23:26:24 +12001034 }
1035 }
1036 else {
Jonathan Hartabad6a52013-09-30 18:17:21 +13001037 calculateAndPushPath(path, macAddress);
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001038 pushedPaths.put(path.getDstIpAddress(), path);
Jonathan Hart309889c2013-08-13 23:26:24 +12001039 }
1040 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001041
Jonathan Hart309889c2013-08-13 23:26:24 +12001042 Set<RibUpdate> prefixesToPush = prefixesWaitingOnArp.removeAll(ipAddress);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001043
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001044 for (RibUpdate update : prefixesToPush) {
1045 //These will always be adds
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001046
1047 RibEntry rib = ptree.lookup(update.getPrefix());
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001048 if (rib != null && rib.equals(update.getRibEntry())) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001049 log.debug("Pushing prefix {} next hop {}", update.getPrefix(),
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001050 rib.getNextHop().getHostAddress());
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001051 //We only push prefix flows if the prefix is still in the ptree
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001052 //and the next hop is the same as our update. The prefix could
1053 //have been removed while we were waiting for the ARP, or the
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001054 //next hop could have changed.
Jonathan Hart309889c2013-08-13 23:26:24 +12001055 _processRibAdd(update);
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001056 } else {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001057 log.debug("Received ARP response, but {},{} is no longer in ptree",
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001058 update.getPrefix(), update.getRibEntry());
1059 }
1060 }
Jonathan Hart0ee0f022013-08-03 22:21:54 +12001061 }
Jonathan Hart4dfc3652013-08-02 20:22:36 +12001062 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001063
pingping-linba5c52f2014-02-11 16:52:01 -08001064 //TODO wait the priority module of the flow Manager
Jonathan Hartc82051c2013-08-24 15:12:20 +12001065 private void setupArpFlows() {
1066 OFMatch match = new OFMatch();
1067 match.setDataLayerType(Ethernet.TYPE_ARP);
1068 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001069
Jonathan Hartc82051c2013-08-24 15:12:20 +12001070 OFFlowMod fm = new OFFlowMod();
1071 fm.setMatch(match);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001072
Jonathan Hartc82051c2013-08-24 15:12:20 +12001073 OFActionOutput action = new OFActionOutput();
1074 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1075 action.setMaxLength((short)0xffff);
1076 List<OFAction> actions = new ArrayList<OFAction>(1);
1077 actions.add(action);
1078 fm.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001079
Jonathan Hartc82051c2013-08-24 15:12:20 +12001080 fm.setIdleTimeout((short)0)
pingping-linba5c52f2014-02-11 16:52:01 -08001081 .setHardTimeout((short)0)
1082 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1083 .setCookie(0)
1084 .setCommand(OFFlowMod.OFPFC_ADD)
1085 .setPriority(ARP_PRIORITY)
Jonathan Hartc82051c2013-08-24 15:12:20 +12001086 .setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001087
Jonathan Hartc82051c2013-08-24 15:12:20 +12001088 for (String strdpid : switches){
Jonathan Hart1912afc2013-10-11 12:02:44 +13001089 flowCache.write(HexString.toLong(strdpid), fm);
Jonathan Hartc82051c2013-08-24 15:12:20 +12001090 }
1091 }
pingping-linba5c52f2014-02-11 16:52:01 -08001092 //TODO need update, waiting for the priority feature from flow Manager
Jonathan Hartf886fa12013-09-18 14:46:29 +12001093 private void setupDefaultDropFlows() {
1094 OFFlowMod fm = new OFFlowMod();
1095 fm.setMatch(new OFMatch());
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001096 fm.setActions(new ArrayList<OFAction>()); //No action means drop
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001097
Jonathan Hartf886fa12013-09-18 14:46:29 +12001098 fm.setIdleTimeout((short)0)
pingping-linba5c52f2014-02-11 16:52:01 -08001099 .setHardTimeout((short)0)
1100 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1101 .setCookie(0)
1102 .setCommand(OFFlowMod.OFPFC_ADD)
1103 .setPriority((short)0)
Jonathan Hartf886fa12013-09-18 14:46:29 +12001104 .setLengthU(OFFlowMod.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001105
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001106 OFFlowMod fmLLDP;
1107 OFFlowMod fmBDDP;
1108 try {
pingping-linba5c52f2014-02-11 16:52:01 -08001109 fmLLDP = fm.clone();
1110 fmBDDP = fm.clone();
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001111 } catch (CloneNotSupportedException e1) {
1112 log.error("Error cloning flow mod", e1);
1113 return;
1114 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001115
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001116 OFMatch matchLLDP = new OFMatch();
Stacey Sheldon44433002014-01-21 00:43:09 -05001117 matchLLDP.setDataLayerType((short)0x88cc);
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001118 matchLLDP.setWildcards(matchLLDP.getWildcards() & ~ OFMatch.OFPFW_DL_TYPE);
1119 fmLLDP.setMatch(matchLLDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001120
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001121 OFMatch matchBDDP = new OFMatch();
Stacey Sheldon44433002014-01-21 00:43:09 -05001122 matchBDDP.setDataLayerType((short)0x8942);
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001123 matchBDDP.setWildcards(matchBDDP.getWildcards() & ~ OFMatch.OFPFW_DL_TYPE);
1124 fmBDDP.setMatch(matchBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001125
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001126 OFActionOutput action = new OFActionOutput();
1127 action.setPort(OFPort.OFPP_CONTROLLER.getValue());
1128 action.setMaxLength((short)0xffff);
1129 List<OFAction> actions = new ArrayList<OFAction>(1);
1130 actions.add(action);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001131
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001132 fmLLDP.setActions(actions);
1133 fmBDDP.setActions(actions);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001134
Jonathan Hart4aa2b4e2013-09-24 14:50:23 +12001135 fmLLDP.setPriority(ARP_PRIORITY);
1136 fmLLDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
1137 fmBDDP.setPriority(ARP_PRIORITY);
1138 fmBDDP.setLengthU(OFFlowMod.MINIMUM_LENGTH + OFActionOutput.MINIMUM_LENGTH);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001139
1140 List<OFFlowMod> flowModList = new ArrayList<OFFlowMod>(3);
Jonathan Hart1912afc2013-10-11 12:02:44 +13001141 flowModList.add(fm);
1142 flowModList.add(fmLLDP);
1143 flowModList.add(fmBDDP);
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001144
Jonathan Hartf886fa12013-09-18 14:46:29 +12001145 for (String strdpid : switches){
Jonathan Hart1912afc2013-10-11 12:02:44 +13001146 flowCache.write(HexString.toLong(strdpid), flowModList);
Jonathan Hartf886fa12013-09-18 14:46:29 +12001147 }
1148 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001149
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001150 private void beginRouting(){
1151 log.debug("Topology is now ready, beginning routing function");
Pavlin Radoslavov15954d42013-10-19 15:29:04 -07001152 topology = topologyNetService.newDatabaseTopology();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001153
pingping-linba5c52f2014-02-11 16:52:01 -08001154 // Wait Pavlin's API. We need the following functions.
1155 /*setupArpFlows();
1156 setupDefaultDropFlows();*/
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001157
Jonathan Hart832a7cb2013-06-24 11:25:35 +12001158 setupBgpPaths();
Jonathan Hart98957bf2013-07-01 14:49:24 +12001159 setupFullMesh();
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001160
Jonathan Harte7694532013-09-12 12:34:46 +12001161 //Suppress link discovery on external-facing router ports
1162 for (Interface intf : interfaces.values()) {
1163 linkDiscoveryService.AddToSuppressLLDPs(intf.getDpid(), intf.getPort());
1164 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001165
Jonathan Hart0a46fe42013-08-10 17:08:47 +12001166 bgpUpdatesExecutor.execute(new Runnable() {
1167 @Override
1168 public void run() {
1169 doUpdatesThread();
1170 }
1171 });
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001172 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001173
pingping-linba5c52f2014-02-11 16:52:01 -08001174 // Before inserting the paths for BGP traffic, we should check
1175 // whether all the switches in the configure file are discovered by onos.
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001176 private void checkSwitchesConnected(){
1177 for (String dpid : switches){
pingping-linba5c52f2014-02-11 16:52:01 -08001178 Iterator<ISwitchObject> activeSwitches = topoSwitchService.
1179 getActiveSwitches().iterator();
1180 while(activeSwitches.hasNext())
1181 {
1182 ISwitchObject switchObject = activeSwitches.next();
1183 if (switchObject.getDPID().equals(dpid)) {
1184 break;
1185 }
1186 if(activeSwitches.hasNext() == false) {
1187 log.debug("Not all switches are here yet");
1188 return;
1189 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001190 }
1191 }
1192 switchesConnected = true;
1193 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001194
Jonathan Hartc824ad02013-07-03 15:58:45 +12001195 //Actually we only need to go half way round to verify full mesh connectivity
1196 //(n^2)/2
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001197 private void checkTopologyReady(){
Jonathan Hartc824ad02013-07-03 15:58:45 +12001198 for (Interface dstInterface : interfaces.values()) {
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001199 for (Interface srcInterface : interfaces.values()) {
Jonathan Hart45107222013-10-22 17:35:04 -07001200 if (dstInterface.equals(srcInterface)) {
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001201 continue;
1202 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001203
Pavlin Radoslavov15954d42013-10-19 15:29:04 -07001204 DataPath shortestPath = topologyNetService.getDatabaseShortestPath(
Jonathan Hartc824ad02013-07-03 15:58:45 +12001205 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001206
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001207 if (shortestPath == null){
1208 log.debug("Shortest path between {} and {} not found",
Jonathan Hartc824ad02013-07-03 15:58:45 +12001209 srcInterface.getSwitchPort(), dstInterface.getSwitchPort());
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001210 return;
1211 }
1212 }
1213 }
1214 topologyReady = true;
1215 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001216
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001217 private void checkStatus(){
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001218 if (!switchesConnected){
1219 checkSwitchesConnected();
1220 }
1221 boolean oldTopologyReadyStatus = topologyReady;
1222 if (switchesConnected && !topologyReady){
1223 checkTopologyReady();
1224 }
1225 if (!oldTopologyReadyStatus && topologyReady){
1226 beginRouting();
1227 }
1228 }
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001229
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001230 private void doUpdatesThread() {
1231 boolean interrupted = false;
1232 try {
1233 while (true) {
1234 try {
1235 RibUpdate update = ribUpdates.take();
1236 switch (update.getOperation()){
1237 case UPDATE:
Jonathan Harte4c98692013-10-18 17:40:03 -07001238 if (validateUpdate(update)) {
1239 processRibAdd(update);
1240 }
1241 else {
1242 log.debug("Rib UPDATE out of order: {} via {}",
1243 update.getPrefix(), update.getRibEntry().getNextHop());
1244 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001245 break;
1246 case DELETE:
Jonathan Harte4c98692013-10-18 17:40:03 -07001247 if (validateUpdate(update)) {
1248 processRibDelete(update);
1249 }
1250 else {
1251 log.debug("Rib DELETE out of order: {} via {}",
1252 update.getPrefix(), update.getRibEntry().getNextHop());
1253 }
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001254 break;
1255 }
1256 } catch (InterruptedException e) {
Jonathan Harta23ffdb2013-08-14 14:36:54 +12001257 log.debug("Interrupted while taking from updates queue", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001258 interrupted = true;
Jonathan Hart309889c2013-08-13 23:26:24 +12001259 } catch (Exception e) {
1260 log.debug("exception", e);
Jonathan Hart8b9349e2013-07-26 15:55:28 +12001261 }
1262 }
1263 } finally {
1264 if (interrupted) {
1265 Thread.currentThread().interrupt();
1266 }
1267 }
1268 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001269
Jonathan Harte4c98692013-10-18 17:40:03 -07001270 private boolean validateUpdate(RibUpdate update) {
1271 RibEntry newEntry = update.getRibEntry();
1272 RibEntry oldEntry = ptree.lookup(update.getPrefix());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001273
Jonathan Harte4c98692013-10-18 17:40:03 -07001274 //If there is no existing entry we must assume this is the most recent
1275 //update. However this might not always be the case as we might have a
1276 //POST then DELETE reordering.
1277 //if (oldEntry == null || !newEntry.getNextHop().equals(oldEntry.getNextHop())) {
1278 if (oldEntry == null) {
1279 return true;
1280 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001281
Jonathan Harte4c98692013-10-18 17:40:03 -07001282 // This handles the case where routes are gathered in the initial
1283 // request because they don't have sequence number info
1284 if (newEntry.getSysUpTime() == -1 && newEntry.getSequenceNum() == -1) {
1285 return true;
1286 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001287
Jonathan Harte4c98692013-10-18 17:40:03 -07001288 if (newEntry.getSysUpTime() > oldEntry.getSysUpTime()) {
1289 return true;
1290 }
1291 else if (newEntry.getSysUpTime() == oldEntry.getSysUpTime()) {
1292 if (newEntry.getSequenceNum() > oldEntry.getSequenceNum()) {
1293 return true;
1294 }
1295 else {
1296 return false;
1297 }
1298 }
1299 else {
1300 return false;
1301 }
1302 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001303
1304 @Override
Jonathan Hart64c0b202013-08-20 15:45:07 +12001305 public void topologyChanged() {
1306 if (topologyReady) {
1307 return;
1308 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001309
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001310 boolean refreshNeeded = false;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -07001311 for (LDUpdate ldu : topologyService.getLastLinkUpdates()){
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001312 if (!ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_UPDATED)){
1313 //We don't need to recalculate anything for just link updates
Jonathan Hartb39a67d2013-08-10 23:59:50 +12001314 //They happen very frequently
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001315 refreshNeeded = true;
1316 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001317
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001318 log.debug("Topo change {}", ldu.getOperation());
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001319
Jonathan Hart98957bf2013-07-01 14:49:24 +12001320 if (ldu.getOperation().equals(ILinkDiscovery.UpdateOperation.LINK_ADDED)){
1321 synchronized (linkUpdates) {
1322 linkUpdates.add(ldu);
1323 }
1324 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001325 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001326
Jonathan Hart64c0b202013-08-20 15:45:07 +12001327 if (refreshNeeded && !topologyReady){
Jonathan Hart98957bf2013-07-01 14:49:24 +12001328 topologyChangeDetectorTask.reschedule(TOPO_DETECTION_WAIT, TimeUnit.SECONDS);
pingping-lina2cbfad2013-03-07 08:39:21 +08001329 }
Jonathan Hart1236a9b2013-06-18 22:10:05 +12001330 }
Jonathan Hart64c0b202013-08-20 15:45:07 +12001331
1332 @Override
1333 public void addedSwitch(IOFSwitch sw) {
1334 if (!topologyReady) {
1335 sw.clearAllFlowMods();
1336 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001337
Jonathan Hart1912afc2013-10-11 12:02:44 +13001338 flowCache.switchConnected(sw);
Jonathan Hart64c0b202013-08-20 15:45:07 +12001339 }
1340
1341 @Override
Jonathan Hart08ee8522013-09-22 17:34:43 +12001342 public void removedSwitch(IOFSwitch sw) {}
Jonathan Hart64c0b202013-08-20 15:45:07 +12001343
1344 @Override
Jonathan Hart08ee8522013-09-22 17:34:43 +12001345 public void switchPortChanged(Long switchId) {}
Jonathan Hart64c0b202013-08-20 15:45:07 +12001346
1347 @Override
1348 public String getName() {
Jonathan Hart08ee8522013-09-22 17:34:43 +12001349 return "BgpRoute";
1350 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001351
Jonathan Hart08ee8522013-09-22 17:34:43 +12001352 /*
Jonathan Harta8887642013-10-28 13:46:54 -07001353 * IConfigInfoService methods
Jonathan Hart08ee8522013-09-22 17:34:43 +12001354 */
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001355
Jonathan Hart08ee8522013-09-22 17:34:43 +12001356 @Override
1357 public boolean isInterfaceAddress(InetAddress address) {
1358 Interface intf = interfacePtrie.match(new Prefix(address.getAddress(), 32));
1359 return (intf != null && intf.getIpAddress().equals(address));
1360 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001361
Jonathan Hart08ee8522013-09-22 17:34:43 +12001362 @Override
1363 public boolean inConnectedNetwork(InetAddress address) {
1364 Interface intf = interfacePtrie.match(new Prefix(address.getAddress(), 32));
1365 return (intf != null && !intf.getIpAddress().equals(address));
1366 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001367
Jonathan Hart08ee8522013-09-22 17:34:43 +12001368 @Override
1369 public boolean fromExternalNetwork(long inDpid, short inPort) {
1370 for (Interface intf : interfaces.values()) {
1371 if (intf.getDpid() == inDpid && intf.getPort() == inPort) {
1372 return true;
1373 }
1374 }
1375 return false;
1376 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001377
Jonathan Hart08ee8522013-09-22 17:34:43 +12001378 @Override
1379 public Interface getOutgoingInterface(InetAddress dstIpAddress) {
1380 return interfacePtrie.match(new Prefix(dstIpAddress.getAddress(), 32));
1381 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001382
Jonathan Hart08ee8522013-09-22 17:34:43 +12001383 @Override
1384 public boolean hasLayer3Configuration() {
1385 return !interfaces.isEmpty();
1386 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001387
Jonathan Hart08ee8522013-09-22 17:34:43 +12001388 @Override
1389 public MACAddress getRouterMacAddress() {
1390 return bgpdMacAddress;
Jonathan Hart64c0b202013-08-20 15:45:07 +12001391 }
Yuta HIGUCHIe7eac182014-03-19 19:18:30 -07001392
Jonathan Harta8887642013-10-28 13:46:54 -07001393 @Override
1394 public short getVlan() {
1395 return vlan;
1396 }
pingping-lina2cbfad2013-03-07 08:39:21 +08001397}