weibit

Merge branch 'master' of ssh://gerrit.onlab.us:29418/onos-next

Showing 29 changed files with 1134 additions and 228 deletions
......@@ -53,11 +53,13 @@ public class HostToInterfaceAdaptor implements InterfaceService {
public Interface getInterface(ConnectPoint connectPoint) {
checkNotNull(connectPoint);
PortAddresses portAddresses =
Set<PortAddresses> portAddresses =
hostService.getAddressBindingsForPort(connectPoint);
if (!portAddresses.ipAddresses().isEmpty()) {
return new Interface(portAddresses);
for (PortAddresses addresses : portAddresses) {
if (addresses.connectPoint().equals(connectPoint)) {
return new Interface(addresses);
}
}
return null;
......
......@@ -23,6 +23,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
......@@ -63,10 +64,6 @@ public class HostToInterfaceAdaptorTest {
private static final ConnectPoint NON_EXISTENT_CP = new ConnectPoint(
DeviceId.deviceId("doesnotexist"), PortNumber.portNumber(1));
private static final PortAddresses DEFAULT_PA = new PortAddresses(
NON_EXISTENT_CP, null, null);
@Before
public void setUp() throws Exception {
hostService = createMock(HostService.class);
......@@ -123,7 +120,8 @@ public class HostToInterfaceAdaptorTest {
MacAddress mac) {
PortAddresses pa = new PortAddresses(cp, ipAddresses, mac);
portAddresses.add(pa);
expect(hostService.getAddressBindingsForPort(cp)).andReturn(pa).anyTimes();
expect(hostService.getAddressBindingsForPort(cp)).andReturn(
Collections.singleton(pa)).anyTimes();
Interface intf = new Interface(cp, ipAddresses, mac);
interfaces.put(cp, intf);
......@@ -158,7 +156,7 @@ public class HostToInterfaceAdaptorTest {
// Try and get an interface for a connect point with no addresses
reset(hostService);
expect(hostService.getAddressBindingsForPort(NON_EXISTENT_CP))
.andReturn(DEFAULT_PA).anyTimes();
.andReturn(Collections.<PortAddresses>emptySet()).anyTimes();
replay(hostService);
assertNull(adaptor.getInterface(NON_EXISTENT_CP));
......
......@@ -34,11 +34,7 @@ public interface HostAdminService {
* Binds IP and MAC addresses to the given connection point.
* <p>
* The addresses are added to the set of addresses already bound to the
* connection point. If any of the fields in addresses is null, no change
* is made to the corresponding addresses in the store.
* {@link #unbindAddressesFromPort(PortAddresses)} must be use to unbind
* addresses that have previously been bound.
* </p>
* connection point.
*
* @param addresses address object containing addresses to add and the port
* to add them to
......
......@@ -135,7 +135,7 @@ public interface HostService {
* @param connectPoint the connection point to retrieve address bindings for
* @return addresses bound to the port
*/
PortAddresses getAddressBindingsForPort(ConnectPoint connectPoint);
Set<PortAddresses> getAddressBindingsForPort(ConnectPoint connectPoint);
/**
* Adds the specified host listener.
......
......@@ -15,6 +15,8 @@
*/
package org.onlab.onos.net.host;
import java.util.Set;
import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.DeviceId;
import org.onlab.onos.net.Host;
......@@ -25,8 +27,6 @@ import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import java.util.Set;
/**
* Manages inventory of end-station hosts; not intended for direct use.
*/
......@@ -153,5 +153,5 @@ public interface HostStore extends Store<HostEvent, HostStoreDelegate> {
* for
* @return address information for the connection point
*/
PortAddresses getAddressBindingsForPort(ConnectPoint connectPoint);
Set<PortAddresses> getAddressBindingsForPort(ConnectPoint connectPoint);
}
......
......@@ -95,7 +95,7 @@ public class HostServiceAdapter implements HostService {
}
@Override
public PortAddresses getAddressBindingsForPort(ConnectPoint connectPoint) {
public Set<PortAddresses> getAddressBindingsForPort(ConnectPoint connectPoint) {
return null;
}
......
......@@ -207,7 +207,7 @@ public class HostManager
}
@Override
public PortAddresses getAddressBindingsForPort(ConnectPoint connectPoint) {
public Set<PortAddresses> getAddressBindingsForPort(ConnectPoint connectPoint) {
return store.getAddressBindingsForPort(connectPoint);
}
......
......@@ -175,13 +175,15 @@ public class HostMonitor implements TimerTask {
for (Device device : deviceService.getDevices()) {
for (Port port : deviceService.getPorts(device.id())) {
ConnectPoint cp = new ConnectPoint(device.id(), port.number());
PortAddresses portAddresses =
Set<PortAddresses> portAddressSet =
hostManager.getAddressBindingsForPort(cp);
for (InterfaceIpAddress ia : portAddresses.ipAddresses()) {
if (ia.subnetAddress().contains(targetIp)) {
sendProbe(device.id(), port, targetIp,
ia.ipAddress(), portAddresses.mac());
for (PortAddresses portAddresses : portAddressSet) {
for (InterfaceIpAddress ia : portAddresses.ipAddresses()) {
if (ia.subnetAddress().contains(targetIp)) {
sendProbe(device.id(), port, targetIp,
ia.ipAddress(), portAddresses.mac());
}
}
}
}
......
......@@ -134,14 +134,16 @@ public class ProxyArpManager implements ProxyArpService {
IpAddress target =
IpAddress.valueOf(IpAddress.Version.INET,
arp.getTargetProtocolAddress());
PortAddresses addresses =
Set<PortAddresses> addressSet =
hostService.getAddressBindingsForPort(inPort);
for (InterfaceIpAddress ia : addresses.ipAddresses()) {
if (ia.ipAddress().equals(target)) {
Ethernet arpReply =
buildArpReply(ia.ipAddress(), addresses.mac(), eth);
sendTo(arpReply, inPort);
for (PortAddresses addresses : addressSet) {
for (InterfaceIpAddress ia : addresses.ipAddresses()) {
if (ia.ipAddress().equals(target)) {
Ethernet arpReply =
buildArpReply(ia.ipAddress(), addresses.mac(), eth);
sendTo(arpReply, inPort);
}
}
}
return;
......@@ -244,7 +246,7 @@ public class ProxyArpManager implements ProxyArpService {
// TODO: Is this sufficient to identify outside-facing ports: just
// having IP addresses on a port?
//
return !hostService.getAddressBindingsForPort(port).ipAddresses().isEmpty();
return !hostService.getAddressBindingsForPort(port).isEmpty();
}
@Override
......
......@@ -234,10 +234,10 @@ public class HostManagerTest {
new PortAddresses(CP1, Sets.newHashSet(IA1, IA2), MAC1);
mgr.bindAddressesToPort(add1);
PortAddresses storedAddresses = mgr.getAddressBindingsForPort(CP1);
Set<PortAddresses> storedAddresses = mgr.getAddressBindingsForPort(CP1);
assertTrue(add1.ipAddresses().equals(storedAddresses.ipAddresses()));
assertTrue(add1.mac().equals(storedAddresses.mac()));
assertEquals(1, storedAddresses.size());
assertTrue(storedAddresses.contains(add1));
// Add some more addresses and check that they're added correctly
PortAddresses add2 =
......@@ -246,18 +246,19 @@ public class HostManagerTest {
mgr.bindAddressesToPort(add2);
storedAddresses = mgr.getAddressBindingsForPort(CP1);
assertTrue(storedAddresses.ipAddresses().equals(
Sets.newHashSet(IA1, IA2, IA3)));
assertTrue(storedAddresses.mac().equals(MAC1));
assertEquals(2, storedAddresses.size());
assertTrue(storedAddresses.contains(add1));
assertTrue(storedAddresses.contains(add2));
PortAddresses add3 = new PortAddresses(CP1, null, MAC2);
mgr.bindAddressesToPort(add3);
storedAddresses = mgr.getAddressBindingsForPort(CP1);
assertTrue(storedAddresses.ipAddresses().equals(
Sets.newHashSet(IA1, IA2, IA3)));
assertTrue(storedAddresses.mac().equals(MAC2));
assertEquals(3, storedAddresses.size());
assertTrue(storedAddresses.contains(add1));
assertTrue(storedAddresses.contains(add2));
assertTrue(storedAddresses.contains(add3));
}
@Test
......@@ -266,10 +267,10 @@ public class HostManagerTest {
new PortAddresses(CP1, Sets.newHashSet(IA1, IA2), MAC1);
mgr.bindAddressesToPort(add1);
PortAddresses storedAddresses = mgr.getAddressBindingsForPort(CP1);
Set<PortAddresses> storedAddresses = mgr.getAddressBindingsForPort(CP1);
assertTrue(storedAddresses.ipAddresses().size() == 2);
assertNotNull(storedAddresses.mac());
assertEquals(1, storedAddresses.size());
assertTrue(storedAddresses.contains(add1));
PortAddresses rem1 =
new PortAddresses(CP1, Sets.newHashSet(IA1), null);
......@@ -277,25 +278,15 @@ public class HostManagerTest {
mgr.unbindAddressesFromPort(rem1);
storedAddresses = mgr.getAddressBindingsForPort(CP1);
assertTrue(storedAddresses.ipAddresses().equals(Sets.newHashSet(IA2)));
assertTrue(storedAddresses.mac().equals(MAC1));
// It shouldn't have been removed because it didn't match the originally
// submitted address object
assertEquals(1, storedAddresses.size());
assertTrue(storedAddresses.contains(add1));
PortAddresses rem2 = new PortAddresses(CP1, null, MAC1);
mgr.unbindAddressesFromPort(rem2);
mgr.unbindAddressesFromPort(add1);
storedAddresses = mgr.getAddressBindingsForPort(CP1);
assertTrue(storedAddresses.ipAddresses().equals(Sets.newHashSet(IA2)));
assertNull(storedAddresses.mac());
PortAddresses rem3 =
new PortAddresses(CP1, Sets.newHashSet(IA2), MAC1);
mgr.unbindAddressesFromPort(rem3);
storedAddresses = mgr.getAddressBindingsForPort(CP1);
assertTrue(storedAddresses.ipAddresses().isEmpty());
assertNull(storedAddresses.mac());
assertTrue(storedAddresses.isEmpty());
}
@Test
......@@ -304,16 +295,15 @@ public class HostManagerTest {
new PortAddresses(CP1, Sets.newHashSet(IA1, IA2), MAC1);
mgr.bindAddressesToPort(add1);
PortAddresses storedAddresses = mgr.getAddressBindingsForPort(CP1);
Set<PortAddresses> storedAddresses = mgr.getAddressBindingsForPort(CP1);
assertTrue(storedAddresses.ipAddresses().size() == 2);
assertNotNull(storedAddresses.mac());
assertEquals(1, storedAddresses.size());
assertTrue(storedAddresses.contains(add1));
mgr.clearAddresses(CP1);
storedAddresses = mgr.getAddressBindingsForPort(CP1);
assertTrue(storedAddresses.ipAddresses().isEmpty());
assertNull(storedAddresses.mac());
assertTrue(storedAddresses.isEmpty());
}
@Test
......@@ -322,12 +312,10 @@ public class HostManagerTest {
new PortAddresses(CP1, Sets.newHashSet(IA1, IA2), MAC1);
mgr.bindAddressesToPort(add1);
PortAddresses storedAddresses = mgr.getAddressBindingsForPort(CP1);
Set<PortAddresses> storedAddresses = mgr.getAddressBindingsForPort(CP1);
assertTrue(storedAddresses.connectPoint().equals(CP1));
assertTrue(storedAddresses.ipAddresses().equals(
Sets.newHashSet(IA1, IA2)));
assertTrue(storedAddresses.mac().equals(MAC1));
assertEquals(1, storedAddresses.size());
assertTrue(storedAddresses.contains(add1));
}
@Test
......
......@@ -20,7 +20,9 @@ import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.expectLastCall;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.junit.Assert.*;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Collections;
......@@ -130,7 +132,7 @@ public class HostMonitorTest {
expect(hostManager.getHostsByIp(TARGET_IP_ADDR))
.andReturn(Collections.<Host>emptySet()).anyTimes();
expect(hostManager.getAddressBindingsForPort(cp))
.andReturn(pa).anyTimes();
.andReturn(Collections.singleton(pa)).anyTimes();
replay(hostManager);
TestPacketService packetService = new TestPacketService();
......
......@@ -19,7 +19,10 @@ import static org.easymock.EasyMock.anyObject;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.junit.Assert.*;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Collections;
......@@ -207,13 +210,18 @@ public class ProxyArpManagerTest {
IpAddress addr2 = IpAddress.valueOf("10.0." + (2 * i) + ".1");
InterfaceIpAddress ia1 = new InterfaceIpAddress(addr1, prefix1);
InterfaceIpAddress ia2 = new InterfaceIpAddress(addr2, prefix2);
PortAddresses pa =
new PortAddresses(cp, Sets.newHashSet(ia1, ia2),
MacAddress.valueOf(i));
addresses.add(pa);
PortAddresses pa1 =
new PortAddresses(cp, Sets.newHashSet(ia1),
MacAddress.valueOf(2 * i - 1));
PortAddresses pa2 =
new PortAddresses(cp, Sets.newHashSet(ia2),
MacAddress.valueOf(2 * i));
addresses.add(pa1);
addresses.add(pa2);
expect(hostService.getAddressBindingsForPort(cp))
.andReturn(pa).anyTimes();
.andReturn(Sets.newHashSet(pa1, pa2)).anyTimes();
}
expect(hostService.getAddressBindings()).andReturn(addresses).anyTimes();
......@@ -222,7 +230,7 @@ public class ProxyArpManagerTest {
ConnectPoint cp = new ConnectPoint(getDeviceId(i + NUM_ADDRESS_PORTS),
P1);
expect(hostService.getAddressBindingsForPort(cp))
.andReturn(new PortAddresses(cp, null, null)).anyTimes();
.andReturn(Collections.<PortAddresses>emptySet()).anyTimes();
}
}
......@@ -339,7 +347,8 @@ public class ProxyArpManagerTest {
IpAddress theirIp = IpAddress.valueOf("10.0.1.254");
IpAddress ourFirstIp = IpAddress.valueOf("10.0.1.1");
IpAddress ourSecondIp = IpAddress.valueOf("10.0.2.1");
MacAddress ourMac = MacAddress.valueOf(1L);
MacAddress firstMac = MacAddress.valueOf(1L);
MacAddress secondMac = MacAddress.valueOf(2L);
Host requestor = new DefaultHost(PID, HID2, MAC2, VLAN1, LOC1,
Collections.singleton(theirIp));
......@@ -352,7 +361,7 @@ public class ProxyArpManagerTest {
proxyArp.reply(arpRequest, LOC1);
assertEquals(1, packetService.packets.size());
Ethernet arpReply = buildArp(ARP.OP_REPLY, ourMac, MAC2, ourFirstIp, theirIp);
Ethernet arpReply = buildArp(ARP.OP_REPLY, firstMac, MAC2, ourFirstIp, theirIp);
verifyPacketOut(arpReply, LOC1, packetService.packets.get(0));
// Test a request for the second address on that port
......@@ -362,7 +371,7 @@ public class ProxyArpManagerTest {
proxyArp.reply(arpRequest, LOC1);
assertEquals(1, packetService.packets.size());
arpReply = buildArp(ARP.OP_REPLY, ourMac, MAC2, ourSecondIp, theirIp);
arpReply = buildArp(ARP.OP_REPLY, secondMac, MAC2, ourSecondIp, theirIp);
verifyPacketOut(arpReply, LOC1, packetService.packets.get(0));
}
......
......@@ -15,12 +15,25 @@
*/
package org.onlab.onos.store.host.impl;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
import static org.onlab.onos.cluster.ControllerNodeToNodeId.toNodeId;
import static org.onlab.onos.net.host.HostEvent.Type.HOST_ADDED;
import static org.onlab.onos.net.host.HostEvent.Type.HOST_MOVED;
import static org.onlab.onos.net.host.HostEvent.Type.HOST_REMOVED;
import static org.onlab.onos.net.host.HostEvent.Type.HOST_UPDATED;
import static org.onlab.util.Tools.namedThreads;
import static org.slf4j.LoggerFactory.getLogger;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.RandomUtils;
import org.apache.felix.scr.annotations.Activate;
......@@ -45,7 +58,6 @@ import org.onlab.onos.net.host.HostDescription;
import org.onlab.onos.net.host.HostEvent;
import org.onlab.onos.net.host.HostStore;
import org.onlab.onos.net.host.HostStoreDelegate;
import org.onlab.onos.net.host.InterfaceIpAddress;
import org.onlab.onos.net.host.PortAddresses;
import org.onlab.onos.net.provider.ProviderId;
import org.onlab.onos.store.AbstractStore;
......@@ -63,21 +75,13 @@ import org.onlab.packet.VlanId;
import org.onlab.util.KryoNamespace;
import org.slf4j.Logger;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
import static org.onlab.onos.cluster.ControllerNodeToNodeId.toNodeId;
import static org.onlab.onos.net.host.HostEvent.Type.*;
import static org.onlab.util.Tools.namedThreads;
import static org.slf4j.LoggerFactory.getLogger;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.google.common.collect.SetMultimap;
//TODO: multi-provider, annotation not supported.
/**
......@@ -100,8 +104,9 @@ public class GossipHostStore
// Hosts tracked by their location
private final Multimap<ConnectPoint, Host> locations = HashMultimap.create();
private final Map<ConnectPoint, PortAddresses> portAddresses =
new ConcurrentHashMap<>();
private final SetMultimap<ConnectPoint, PortAddresses> portAddresses =
Multimaps.synchronizedSetMultimap(
HashMultimap.<ConnectPoint, PortAddresses>create());
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected HostClockService hostClockService;
......@@ -343,77 +348,37 @@ public class GossipHostStore
@Override
public void updateAddressBindings(PortAddresses addresses) {
synchronized (portAddresses) {
PortAddresses existing = portAddresses.get(addresses.connectPoint());
if (existing == null) {
portAddresses.put(addresses.connectPoint(), addresses);
} else {
Set<InterfaceIpAddress> union =
Sets.union(existing.ipAddresses(),
addresses.ipAddresses()).immutableCopy();
MacAddress newMac = (addresses.mac() == null) ? existing.mac()
: addresses.mac();
PortAddresses newAddresses =
new PortAddresses(addresses.connectPoint(), union, newMac);
portAddresses.put(newAddresses.connectPoint(), newAddresses);
}
}
portAddresses.put(addresses.connectPoint(), addresses);
}
@Override
public void removeAddressBindings(PortAddresses addresses) {
synchronized (portAddresses) {
PortAddresses existing = portAddresses.get(addresses.connectPoint());
if (existing != null) {
Set<InterfaceIpAddress> difference =
Sets.difference(existing.ipAddresses(),
addresses.ipAddresses()).immutableCopy();
// If they removed the existing mac, set the new mac to null.
// Otherwise, keep the existing mac.
MacAddress newMac = existing.mac();
if (addresses.mac() != null && addresses.mac().equals(existing.mac())) {
newMac = null;
}
PortAddresses newAddresses =
new PortAddresses(addresses.connectPoint(), difference, newMac);
portAddresses.put(newAddresses.connectPoint(), newAddresses);
}
}
portAddresses.remove(addresses.connectPoint(), addresses);
}
@Override
public void clearAddressBindings(ConnectPoint connectPoint) {
synchronized (portAddresses) {
portAddresses.remove(connectPoint);
}
portAddresses.removeAll(connectPoint);
}
@Override
public Set<PortAddresses> getAddressBindings() {
synchronized (portAddresses) {
return new HashSet<>(portAddresses.values());
return ImmutableSet.copyOf(portAddresses.values());
}
}
@Override
public PortAddresses getAddressBindingsForPort(ConnectPoint connectPoint) {
PortAddresses addresses;
public Set<PortAddresses> getAddressBindingsForPort(ConnectPoint connectPoint) {
synchronized (portAddresses) {
addresses = portAddresses.get(connectPoint);
}
Set<PortAddresses> addresses = portAddresses.get(connectPoint);
if (addresses == null) {
addresses = new PortAddresses(connectPoint, null, null);
if (addresses == null) {
return Collections.emptySet();
} else {
return ImmutableSet.copyOf(addresses);
}
}
return addresses;
}
// Auxiliary extension to allow location to mutate.
......
......@@ -447,13 +447,16 @@ implements MastershipStore {
RoleValue oldValue = event.getOldValue();
RoleValue newValue = event.getValue();
// There will be no oldValue at the very first instance of an EntryEvent.
// Technically, the progression is: null event -> null master -> some master;
// We say a null master and a null oldValue are the same condition.
NodeId oldMaster = null;
if (oldValue != null) {
oldMaster = oldValue.get(MASTER);
}
NodeId newMaster = newValue.get(MASTER);
if (Objects.equal(oldMaster, newMaster)) {
if (!Objects.equal(oldMaster, newMaster)) {
notifyDelegate(new MastershipEvent(
MASTER_CHANGED, event.getKey(), event.getValue().roleInfo()));
} else {
......
......@@ -15,10 +15,18 @@
*/
package org.onlab.onos.store.trivial.impl;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import static org.onlab.onos.net.host.HostEvent.Type.HOST_ADDED;
import static org.onlab.onos.net.host.HostEvent.Type.HOST_MOVED;
import static org.onlab.onos.net.host.HostEvent.Type.HOST_REMOVED;
import static org.onlab.onos.net.host.HostEvent.Type.HOST_UPDATED;
import static org.slf4j.LoggerFactory.getLogger;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
......@@ -34,7 +42,6 @@ import org.onlab.onos.net.host.HostDescription;
import org.onlab.onos.net.host.HostEvent;
import org.onlab.onos.net.host.HostStore;
import org.onlab.onos.net.host.HostStoreDelegate;
import org.onlab.onos.net.host.InterfaceIpAddress;
import org.onlab.onos.net.host.PortAddresses;
import org.onlab.onos.net.provider.ProviderId;
import org.onlab.onos.store.AbstractStore;
......@@ -43,13 +50,11 @@ import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.slf4j.Logger;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import static org.onlab.onos.net.host.HostEvent.Type.*;
import static org.slf4j.LoggerFactory.getLogger;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.google.common.collect.SetMultimap;
// TODO: multi-provider, annotation not supported.
/**
......@@ -70,8 +75,9 @@ public class SimpleHostStore
// Hosts tracked by their location
private final Multimap<ConnectPoint, Host> locations = HashMultimap.create();
private final Map<ConnectPoint, PortAddresses> portAddresses =
new ConcurrentHashMap<>();
private final SetMultimap<ConnectPoint, PortAddresses> portAddresses =
Multimaps.synchronizedSetMultimap(
HashMultimap.<ConnectPoint, PortAddresses>create());
@Activate
public void activate() {
......@@ -213,77 +219,37 @@ public class SimpleHostStore
@Override
public void updateAddressBindings(PortAddresses addresses) {
synchronized (portAddresses) {
PortAddresses existing = portAddresses.get(addresses.connectPoint());
if (existing == null) {
portAddresses.put(addresses.connectPoint(), addresses);
} else {
Set<InterfaceIpAddress> union =
Sets.union(existing.ipAddresses(),
addresses.ipAddresses()).immutableCopy();
MacAddress newMac = (addresses.mac() == null) ? existing.mac()
: addresses.mac();
PortAddresses newAddresses =
new PortAddresses(addresses.connectPoint(), union, newMac);
portAddresses.put(newAddresses.connectPoint(), newAddresses);
}
}
portAddresses.put(addresses.connectPoint(), addresses);
}
@Override
public void removeAddressBindings(PortAddresses addresses) {
synchronized (portAddresses) {
PortAddresses existing = portAddresses.get(addresses.connectPoint());
if (existing != null) {
Set<InterfaceIpAddress> difference =
Sets.difference(existing.ipAddresses(),
addresses.ipAddresses()).immutableCopy();
// If they removed the existing mac, set the new mac to null.
// Otherwise, keep the existing mac.
MacAddress newMac = existing.mac();
if (addresses.mac() != null && addresses.mac().equals(existing.mac())) {
newMac = null;
}
PortAddresses newAddresses =
new PortAddresses(addresses.connectPoint(), difference, newMac);
portAddresses.put(newAddresses.connectPoint(), newAddresses);
}
}
portAddresses.remove(addresses.connectPoint(), addresses);
}
@Override
public void clearAddressBindings(ConnectPoint connectPoint) {
synchronized (portAddresses) {
portAddresses.remove(connectPoint);
}
portAddresses.removeAll(connectPoint);
}
@Override
public Set<PortAddresses> getAddressBindings() {
synchronized (portAddresses) {
return new HashSet<>(portAddresses.values());
return ImmutableSet.copyOf(portAddresses.values());
}
}
@Override
public PortAddresses getAddressBindingsForPort(ConnectPoint connectPoint) {
PortAddresses addresses;
public Set<PortAddresses> getAddressBindingsForPort(ConnectPoint connectPoint) {
synchronized (portAddresses) {
addresses = portAddresses.get(connectPoint);
}
Set<PortAddresses> addresses = portAddresses.get(connectPoint);
if (addresses == null) {
addresses = new PortAddresses(connectPoint, null, null);
if (addresses == null) {
return Collections.emptySet();
} else {
return ImmutableSet.copyOf(addresses);
}
}
return addresses;
}
// Auxiliary extension to allow location to mutate.
......
......@@ -5,7 +5,7 @@ export ONOS_ROOT=${ONOS_ROOT:-~/onos-next}
# M2 repository and Karaf gold bits
export M2_REPO=${M2_REPO:-~/.m2/repository}
export KARAF_VERSION=${KARAF_VERSION:-3.0.1}
export KARAF_VERSION=${KARAF_VERSION:-3.0.2}
export KARAF_ZIP=${KARAF_ZIP:-~/Downloads/apache-karaf-$KARAF_VERSION.zip}
export KARAF_TAR=${KARAF_TAR:-~/Downloads/apache-karaf-$KARAF_VERSION.tar.gz}
export KARAF_DIST=$(basename $KARAF_ZIP .zip)
......
......@@ -8,7 +8,9 @@ export ONOS_ROOT=${ONOS_ROOT:-~/onos-next}
# Setup some environmental context for developers
if [ -z "${JAVA_HOME}" ]; then
if [ -x /usr/libexec/java_home ]; then
export JAVA_HOME=$(/usr/libexec/java_home -v 1.7)
export JAVA_HOME=$(/usr/libexec/java_home -v 1.8)
elif [ -d /usr/lib/jvm/java-8-oracle ]; then
export JAVA_HOME="/usr/lib/jvm/java-8-oracle"
elif [ -d /usr/lib/jvm/java-7-openjdk-amd64 ]; then
export JAVA_HOME="/usr/lib/jvm/java-7-openjdk-amd64"
fi
......@@ -16,7 +18,7 @@ fi
export MAVEN=${MAVEN:-~/Applications/apache-maven-3.2.2}
export KARAF_VERSION=${KARAF_VERSION:-3.0.1}
export KARAF_VERSION=${KARAF_VERSION:-3.0.2}
export KARAF=${KARAF:-~/Applications/apache-karaf-$KARAF_VERSION}
export KARAF_LOG=$KARAF/data/log/karaf.log
......
......@@ -6,4 +6,4 @@ export OC2="192.168.56.102"
export OCN="192.168.56.103"
export OCI="${OC1}"
export ONOS_FEATURES="${ONOS_FEATURES:-webconsole,onos-api,onos-core,onos-cli,onos-openflow,onos-rest,onos-app-fwd,onos-app-proxyarp,onos-app-tvue}"
export ONOS_FEATURES="${ONOS_FEATURES:-webconsole,onos-api,onos-core,onos-cli,onos-openflow,onos-gui,onos-rest,onos-app-fwd,onos-app-proxyarp,onos-app-tvue}"
......
......@@ -7,4 +7,4 @@ export OC3="192.168.56.104"
export OCN="192.168.56.103"
export OCI="${OC1}"
export ONOS_FEATURES=""
export ONOS_FEATURES="${ONOS_FEATURES:-webconsole,onos-api,onos-core,onos-cli,onos-openflow,onos-gui,onos-rest,onos-app-fwd,onos-app-proxyarp,onos-app-tvue}"
......
/*
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
Geometry library - based on work by Mike Bostock.
*/
(function() {
if (typeof geo == 'undefined') {
geo = {};
}
var tolerance = 1e-10;
function eq(a, b) {
return (Math.abs(a - b) < tolerance);
}
function gt(a, b) {
return (a - b > -tolerance);
}
function lt(a, b) {
return gt(b, a);
}
geo.eq = eq;
geo.gt = gt;
geo.lt = lt;
geo.LineSegment = function(x1, y1, x2, y2) {
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
// Ax + By = C
this.a = y2 - y1;
this.b = x1 - x2;
this.c = x1 * this.a + y1 * this.b;
if (eq(this.a, 0) && eq(this.b, 0)) {
throw new Error(
'Cannot construct a LineSegment with two equal endpoints.');
}
};
geo.LineSegment.prototype.intersect = function(that) {
var d = (this.x1 - this.x2) * (that.y1 - that.y2) -
(this.y1 - this.y2) * (that.x1 - that.x2);
if (eq(d, 0)) {
// The two lines are parallel or very close.
return {
x : NaN,
y : NaN
};
}
var t1 = this.x1 * this.y2 - this.y1 * this.x2,
t2 = that.x1 * that.y2 - that.y1 * that.x2,
x = (t1 * (that.x1 - that.x2) - t2 * (this.x1 - this.x2)) / d,
y = (t1 * (that.y1 - that.y2) - t2 * (this.y1 - this.y2)) / d,
in1 = (gt(x, Math.min(this.x1, this.x2)) && lt(x, Math.max(this.x1, this.x2)) &&
gt(y, Math.min(this.y1, this.y2)) && lt(y, Math.max(this.y1, this.y2))),
in2 = (gt(x, Math.min(that.x1, that.x2)) && lt(x, Math.max(that.x1, that.x2)) &&
gt(y, Math.min(that.y1, that.y2)) && lt(y, Math.max(that.y1, that.y2)));
return {
x : x,
y : y,
in1 : in1,
in2 : in2
};
};
geo.LineSegment.prototype.x = function(y) {
// x = (C - By) / a;
if (this.a) {
return (this.c - this.b * y) / this.a;
} else {
// a == 0 -> horizontal line
return NaN;
}
};
geo.LineSegment.prototype.y = function(x) {
// y = (C - Ax) / b;
if (this.b) {
return (this.c - this.a * x) / this.b;
} else {
// b == 0 -> vertical line
return NaN;
}
};
geo.LineSegment.prototype.length = function() {
return Math.sqrt(
(this.y2 - this.y1) * (this.y2 - this.y1) +
(this.x2 - this.x1) * (this.x2 - this.x1));
};
geo.LineSegment.prototype.offset = function(x, y) {
return new geo.LineSegment(
this.x1 + x, this.y1 + y,
this.x2 + x, this.y2 + y);
};
})();
<!DOCTYPE html>
<!--
~ Copyright 2014 Open Networking Laboratory
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<!--
ONOS UI - single page web app
Version 1.1
@author Simon Hunt
-->
<html>
<head>
<meta charset="utf-8">
<title>ONOS GUI (v1.1)</title>
<link rel="shortcut icon" href="img/onos-logo.png">
<!-- first script to be run -->
<script src="preamble.js"></script>
<!-- Third party library code included here -->
<!--TODO: use the minified version of d3, once debugging is complete -->
<script src="libs/d3.js"></script>
<script src="libs/jquery-2.1.1.min.js"></script>
<!-- Base library and framework stylesheets included here -->
<link rel="stylesheet" href="base.css">
<link rel="stylesheet" href="onos2.css">
<link rel="stylesheet" href="mast2.css">
<!-- This is where contributed stylesheets get INJECTED -->
<!-- TODO: replace with template marker and inject refs server-side -->
<link rel="stylesheet" href="topo2.css">
<!-- General library modules included here-->
<script src="geometry2.js"></script>
<!-- ONOS UI Framework included here-->
<script src="onos2.js"></script>
</head>
<body>
<div id="frame">
<div id="mast">
<!-- NOTE: masthead injected here by mast.js -->
</div>
<div id="view">
<!-- NOTE: views injected here by onos.js -->
</div>
<div id="overlays">
<!-- NOTE: overlays injected here, as needed -->
</div>
</div>
<!-- Initialize the UI...-->
<script type="text/javascript">
var ONOS = $.onos({note: "config, if needed"});
</script>
<!-- Framework module files included here -->
<script src="mast2.js"></script>
<!-- Contributed (application) views injected here -->
<!-- TODO: replace with template marker and inject refs server-side -->
<script src="temp2.js"></script>
<!-- finally, build the UI-->
<script type="text/javascript">
$(ONOS.buildUi);
</script>
</body>
</html>
/*
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
ONOS GUI -- Masthead -- CSS file
@author Simon Hunt
*/
#mast {
height: 36px;
padding: 4px;
background-color: #bbb;
vertical-align: baseline;
box-shadow: 0px 2px 8px #777;
}
#mast img#logo {
height: 38px;
padding-left: 8px;
padding-right: 8px;
}
#mast span.title {
color: #369;
font-size: 14pt;
font-style: italic;
vertical-align: 12px;
}
#mast span.right {
padding-top: 8px;
padding-right: 16px;
float: right;
}
#mast span.radio {
color: darkslateblue;
font-size: 10pt;
}
#mast span.radio {
margin: 4px 0;
border: 1px dotted #222;
padding: 1px 6px;
color: #eee;
cursor: pointer;
}
#mast span.radio.active {
background-color: #bbb;
border: 1px solid #eee;
padding: 1px 6px;
color: #666;
font-weight: bold;
}
/*
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
ONOS GUI -- Masthead
Defines the masthead for the UI. Injects logo and title, as well as providing
the placeholder for a set of radio buttons.
@author Simon Hunt
*/
(function (onos){
'use strict';
// API's
var api = onos.api;
// Config variables
var guiTitle = 'Open Networking Operating System';
// DOM elements and the like
var mast = d3.select('#mast');
mast.append('img')
.attr({
id: 'logo',
src: 'img/onos-logo.png'
});
mast.append('span')
.attr({
class: 'title'
})
.text(guiTitle);
mast.append('span')
.attr({
id: 'mastRadio',
class: 'right'
});
}(ONOS));
\ No newline at end of file
/*
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
ONOS GUI -- Base Framework -- CSS file
@author Simon Hunt
*/
html, body {
height: 100%;
}
/*
* === DEBUGGING ======
*/
svg {
/*border: 1px dashed red;*/
}
svg #bg {
opacity: 0.5;
}
/*
* Network Graph elements ======================================
*/
svg .link {
fill: none;
stroke: #666;
stroke-width: 2.0px;
opacity: .7;
transition: opacity 250ms;
-webkit-transition: opacity 250ms;
-moz-transition: opacity 250ms;
}
svg .link.host {
stroke: #666;
stroke-width: 1px;
}
svg g.portLayer rect.port {
fill: #ccc;
}
svg g.portLayer text {
font: 8pt sans-serif;
pointer-events: none;
}
svg .node.device rect {
stroke-width: 1.5px;
transition: opacity 250ms;
-webkit-transition: opacity 250ms;
-moz-transition: opacity 250ms;
}
svg .node.device.fixed rect {
stroke-width: 1.5;
stroke: #ccc;
}
svg .node.device.roadm rect {
fill: #03c;
}
svg .node.device.switch rect {
fill: #06f;
}
svg .node.host circle {
fill: #c96;
stroke: #000;
}
svg .node text {
fill: white;
font: 10pt sans-serif;
pointer-events: none;
}
/* for debugging */
svg .node circle.debug {
fill: white;
stroke: red;
}
svg .node rect.debug {
fill: yellow;
stroke: red;
opacity: 0.35;
}
svg .node.selected rect,
svg .node.selected circle {
filter: url(#blue-glow);
}
svg .link.inactive,
svg .port.inactive,
svg .portText.inactive,
svg .node.inactive rect,
svg .node.inactive circle,
svg .node.inactive text,
svg .node.inactive image {
opacity: .1;
}
svg .node.inactive.selected rect,
svg .node.inactive.selected text,
svg .node.inactive.selected image {
opacity: .6;
}
/*
* =============================================================
*/
/*
* Specific structural elements
*/
/* This is to ensure that the body does not expand to account for the
flyout details pane, that is positioned "off screen".
*/
body {
overflow: hidden;
}
#frame {
width: 100%;
height: 100%;
background-color: #fff;
}
#flyout {
position: absolute;
z-index: 100;
display: block;
top: 10%;
width: 280px;
right: -300px;
opacity: 0;
background-color: rgba(255,255,255,0.8);
padding: 10px;
color: black;
font-size: 10pt;
box-shadow: 2px 2px 16px #777;
}
#flyout h2 {
margin: 8px 4px;
color: black;
vertical-align: middle;
}
#flyout h2 img {
height: 32px;
padding-right: 8px;
vertical-align: middle;
}
#flyout p, table {
margin: 4px 4px;
}
#flyout td.label {
font-style: italic;
color: #777;
padding-right: 12px;
}
#flyout td.value {
}
#flyout hr {
height: 1px;
color: #ccc;
background-color: #ccc;
border: 0;
}
/*
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
ONOS GUI -- Base Framework
@author Simon Hunt
*/
(function ($) {
'use strict';
var tsI = new Date().getTime(), // initialize time stamp
tsB, // build time stamp
defaultHash = 'temp1';
// attach our main function to the jQuery object
$.onos = function (options) {
var publicApi; // public api
// internal state
var views = {},
current = {
view: null,
ctx: ''
},
built = false,
errorCount = 0;
// DOM elements etc.
var $view;
// ..........................................................
// Internal functions
// throw an error
function throwError(msg) {
// separate function, as we might add tracing here too, later
throw new Error(msg);
}
function doError(msg) {
errorCount++;
console.warn(msg);
}
// hash navigation
function hash() {
var hash = window.location.hash,
redo = false,
view,
t;
if (!hash) {
hash = defaultHash;
redo = true;
}
t = parseHash(hash);
if (!t || !t.vid) {
doError('Unable to parse target hash: ' + hash);
}
view = views[t.vid];
if (!view) {
doError('No view defined with id: ' + t.vid);
}
if (redo) {
window.location.hash = makeHash(t);
// the above will result in a hashchange event, invoking
// this function again
} else {
// hash was not modified... navigate to where we need to be
navigate(hash, view, t);
}
}
function parseHash(s) {
// extract navigation coordinates from the supplied string
// "vid,ctx" --> { vid:vid, ctx:ctx }
var m = /^[#]{0,1}(\S+),(\S*)$/.exec(s);
if (m) {
return { vid: m[1], ctx: m[2] };
}
m = /^[#]{0,1}(\S+)$/.exec(s);
return m ? { vid: m[1] } : null;
}
function makeHash(t, ctx) {
// make a hash string from the given navigation coordinates.
// if t is not an object, then it is a vid
var h = t,
c = ctx || '';
if ($.isPlainObject(t)) {
h = t.vid;
c = t.ctx || '';
}
if (c) {
h += ',' + c;
}
return h;
}
function navigate(hash, view, t) {
// closePanes() // flyouts etc.
// updateNav() // accordion / selected nav item
createView(view);
setView(view, hash, t);
}
function reportBuildErrors() {
// TODO: validate registered views / nav-item linkage etc.
console.log('(no build errors)');
}
// ..........................................................
// View life-cycle functions
function createView(view) {
var $d;
// lazy initialization of the view
if (view && !view.$div) {
$d = $view.append('div')
.attr({
id: view.vid
});
view.$div = $d; // cache a reference to the selected div
}
}
function setView(view, hash, t) {
// set the specified view as current, while invoking the
// appropriate life-cycle callbacks
// if there is a current view, and it is not the same as
// the incoming view, then unload it...
if (current.view && !(current.view.vid !== view.vid)) {
current.view.unload();
}
// cache new view and context
current.view = view;
current.ctx = t.ctx || '';
// TODO: clear radio button set (store on view?)
// preload is called only once, after the view is in the DOM
if (!view.preloaded) {
view.preload(t.ctx);
}
// clear the view of stale data
view.reset();
// load the view
view.load(t.ctx);
}
function resizeView() {
if (current.view) {
current.view.resize();
}
}
// ..........................................................
// View class
// Captures state information about a view.
// Constructor
// vid : view id
// nid : id of associated nav-item (optional)
// cb : callbacks (preload, reset, load, resize, unload, error)
// data: custom data object (optional)
function View(vid) {
var av = 'addView(): ',
args = Array.prototype.slice.call(arguments),
nid,
cb,
data;
args.shift(); // first arg is always vid
if (typeof args[0] === 'string') { // nid specified
nid = args.shift();
}
cb = args.shift();
data = args.shift();
this.vid = vid;
if (validateViewArgs(vid)) {
this.nid = nid; // explicit navitem id (can be null)
this.cb = $.isPlainObject(cb) ? cb : {}; // callbacks
this.data = data; // custom data (can be null)
this.$div = null; // view not yet added to DOM
this.ok = true; // valid view
}
}
function validateViewArgs(vid) {
var ok = false;
if (typeof vid !== 'string' || !vid) {
doError(av + 'vid required');
} else if (views[vid]) {
doError(av + 'View ID "' + vid + '" already exists');
} else {
ok = true;
}
return ok;
}
var viewInstanceMethods = {
toString: function () {
return '[View: id="' + this.vid + '"]';
},
token: function() {
return {
vid: this.vid,
nid: this.nid,
data: this.data
}
}
// TODO: create, preload, reset, load, error, resize, unload
};
// attach instance methods to the view prototype
$.extend(View.prototype, viewInstanceMethods);
// ..........................................................
// Exported API
publicApi = {
printTime: function () {
console.log("the time is " + new Date());
},
addView: function (vid, nid, cb, data) {
var view = new View(vid, nid, cb, data),
token;
if (view.ok) {
views[vid] = view;
token = view.token();
} else {
token = { vid: view.vid, bad: true };
}
return token;
}
};
// function to be called from index.html to build the ONOS UI
function buildOnosUi() {
tsB = new Date().getTime();
tsI = tsB - tsI; // initialization duration
console.log('ONOS UI initialized in ' + tsI + 'ms');
if (built) {
throwError("ONOS UI already built!");
}
built = true;
$view = d3.select('#view');
$(window).on('hashchange', hash);
// Invoke hashchange callback to navigate to content
// indicated by the window location hash.
hash();
// If there were any build errors, report them
reportBuildErrors();
}
// export the api and build-UI function
return {
api: publicApi,
buildUi: buildOnosUi
};
};
}(jQuery));
\ No newline at end of file
/*
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
ONOS GUI -- Preamble -- the first thing we do
@author Simon Hunt
*/
(function () {
// Check if the URL in the address bar contains a parameter section
// (delineated by '?'). If this is the case, rewrite using '#' instead.
var m = /([^?]*)\?(.*)/.exec(window.location.href);
if (m) {
window.location.href = m[1] + '#' + m[2];
}
}());
/*
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
Temporary module file to test the framework integration.
@author Simon Hunt
*/
(function (onos) {
'use strict';
var api = onos.api;
var vid,
svg;
// == define your functions here.....
// NOTE: view is a data structure:
// {
// id: 'view-id',
// el: ... // d3 selection of dom view div.
// }
function load(view) {
vid = view.id;
svg = view.el.append('svg')
.attr({
width: 400,
height: 300
});
var fill = (vid === 'temp1') ? 'red' : 'blue',
stroke = (vid === 'temp2') ? 'yellow' : 'black';
svg.append('circle')
.attr({
cx: 200,
cy: 150,
r: 30
})
.style({
fill: fill,
stroke: stroke,
'stroke-width': 3.5
});
}
// == register views here, with links to lifecycle callbacks
api.addView('temp1', {
load: load
});
api.addView('temp2', {
load: load
});
}(ONOS));
/*
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
ONOS GUI -- Topology view -- CSS file
@author Simon Hunt
*/
This diff is collapsed. Click to expand it.