Merge remote-tracking branch 'origin/master' into dev/murrelet
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp4HandlerImpl.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp4HandlerImpl.java
index f3835c0..ccdb407 100644
--- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp4HandlerImpl.java
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/Dhcp4HandlerImpl.java
@@ -119,6 +119,14 @@
private Ip4Address dhcpGatewayIp = null;
private Ip4Address relayAgentIp = null;
+ // Indirect case DHCP server
+ private Ip4Address indirectDhcpServerIp = null;
+ private ConnectPoint indirectDhcpServerConnectPoint = null;
+ private MacAddress indirectDhcpConnectMac = null;
+ private VlanId indirectDhcpConnectVlan = null;
+ private Ip4Address indirectDhcpGatewayIp = null;
+ private Ip4Address indirectRelayAgentIp = null;
+
@Activate
protected void activate() {
hostService.addListener(hostListener);
@@ -126,15 +134,25 @@
@Deactivate
protected void deactivate() {
+ if (dhcpGatewayIp != null) {
+ hostService.stopMonitoringIp(dhcpGatewayIp);
+ }
+ if (dhcpServerIp != null) {
+ hostService.stopMonitoringIp(dhcpServerIp);
+ }
+
+ if (indirectDhcpGatewayIp != null) {
+ hostService.stopMonitoringIp(indirectDhcpGatewayIp);
+ }
+ if (indirectDhcpServerIp != null) {
+ hostService.stopMonitoringIp(indirectDhcpServerIp);
+ }
+
hostService.removeListener(hostListener);
this.dhcpConnectMac = null;
this.dhcpConnectVlan = null;
-
- if (dhcpGatewayIp != null) {
- hostService.stopMonitoringIp(dhcpGatewayIp);
- } else if (dhcpServerIp != null) {
- hostService.stopMonitoringIp(dhcpServerIp);
- }
+ this.indirectDhcpConnectMac = null;
+ this.indirectDhcpConnectVlan = null;
}
@Override
@@ -248,7 +266,53 @@
@Override
public void setIndirectDhcpServerConfigs(Collection<DhcpServerConfig> configs) {
- log.warn("Indirect config feature for DHCPv4 handler not implement yet");
+ if (configs.size() == 0) {
+ // no config to update
+ return;
+ }
+
+ // TODO: currently we pick up first indirect DHCP server config.
+ // Will use other server configs in the future for HA.
+ DhcpServerConfig serverConfig = configs.iterator().next();
+ checkState(serverConfig.getDhcpServerConnectPoint().isPresent(),
+ "Connect point not exists");
+ checkState(serverConfig.getDhcpServerIp4().isPresent(),
+ "IP of DHCP server not exists");
+ Ip4Address oldServerIp = this.indirectDhcpServerIp;
+ Ip4Address oldGatewayIp = this.indirectDhcpGatewayIp;
+
+ // stop monitoring gateway or server
+ if (oldGatewayIp != null) {
+ hostService.stopMonitoringIp(oldGatewayIp);
+ } else if (oldServerIp != null) {
+ hostService.stopMonitoringIp(oldServerIp);
+ }
+
+ this.indirectDhcpServerConnectPoint = serverConfig.getDhcpServerConnectPoint().get();
+ this.indirectDhcpServerIp = serverConfig.getDhcpServerIp4().get();
+ this.indirectDhcpGatewayIp = serverConfig.getDhcpGatewayIp4().orElse(null);
+
+ // reset server mac and vlan
+ this.indirectDhcpConnectMac = null;
+ this.indirectDhcpConnectVlan = null;
+
+ log.info("Indirect DHCP server connect point: " + this.indirectDhcpServerConnectPoint);
+ log.info("Indirect DHCP server IP: " + this.indirectDhcpServerIp);
+
+ IpAddress ipToProbe = MoreObjects.firstNonNull(this.indirectDhcpGatewayIp, this.indirectDhcpServerIp);
+ String hostToProbe = this.indirectDhcpGatewayIp != null ? "gateway" : "DHCP server";
+
+ log.info("Probing to resolve {} IP {}", hostToProbe, ipToProbe);
+ hostService.startMonitoringIp(ipToProbe);
+
+ Set<Host> hosts = hostService.getHostsByIp(ipToProbe);
+ if (!hosts.isEmpty()) {
+ Host host = hosts.iterator().next();
+ this.indirectDhcpConnectVlan = host.vlan();
+ this.indirectDhcpConnectMac = host.mac();
+ }
+
+ this.indirectRelayAgentIp = serverConfig.getRelayAgentIp4().orElse(null);
}
@Override
@@ -284,7 +348,7 @@
processDhcpPacketFromClient(context, packet);
if (ethernetPacketDiscover != null) {
writeRequestDhcpRecord(inPort, packet, dhcpPayload);
- handleDhcpDiscoverAndRequest(ethernetPacketDiscover);
+ handleDhcpDiscoverAndRequest(ethernetPacketDiscover, dhcpPayload);
}
break;
case DHCPOFFER:
@@ -302,7 +366,7 @@
processDhcpPacketFromClient(context, packet);
if (ethernetPacketRequest != null) {
writeRequestDhcpRecord(inPort, packet, dhcpPayload);
- handleDhcpDiscoverAndRequest(ethernetPacketRequest);
+ handleDhcpDiscoverAndRequest(ethernetPacketRequest, dhcpPayload);
}
break;
case DHCPACK:
@@ -343,7 +407,7 @@
*
* @return true if all information we need have been initialized
*/
- public boolean configured() {
+ private boolean configured() {
return dhcpServerConnectPoint != null && dhcpServerIp != null;
}
@@ -365,25 +429,53 @@
}
/**
- * Gets Interface facing to the server.
+ * Gets Interface facing to the server for default host.
*
* @return the Interface facing to the server; null if not found
*/
- public Interface getServerInterface() {
+ private Interface getServerInterface() {
if (dhcpServerConnectPoint == null || dhcpConnectVlan == null) {
return null;
}
return interfaceService.getInterfacesByPort(dhcpServerConnectPoint)
.stream()
- .filter(iface -> iface.vlan().equals(dhcpConnectVlan) ||
- iface.vlanUntagged().equals(dhcpConnectVlan) ||
- iface.vlanTagged().contains(dhcpConnectVlan) ||
- iface.vlanNative().equals(dhcpConnectVlan))
+ .filter(iface -> interfaceContainsVlan(iface, dhcpConnectVlan))
.findFirst()
.orElse(null);
}
/**
+ * Gets Interface facing to the server for indirect hosts.
+ * Use default server Interface if indirect server not configured.
+ *
+ * @return the Interface facing to the server; null if not found
+ */
+ private Interface getIndirectServerInterface() {
+ if (indirectDhcpServerConnectPoint == null || indirectDhcpConnectVlan == null) {
+ return getServerInterface();
+ }
+ return interfaceService.getInterfacesByPort(indirectDhcpServerConnectPoint)
+ .stream()
+ .filter(iface -> interfaceContainsVlan(iface, indirectDhcpConnectVlan))
+ .findFirst()
+ .orElse(null);
+ }
+
+ /**
+ * Determind if an Interface contains a vlan id.
+ *
+ * @param iface the Interface
+ * @param vlanId the vlan id
+ * @return true if the Interface contains the vlan id
+ */
+ private boolean interfaceContainsVlan(Interface iface, VlanId vlanId) {
+ return iface.vlan().equals(vlanId) ||
+ iface.vlanUntagged().equals(vlanId) ||
+ iface.vlanTagged().contains(vlanId) ||
+ iface.vlanNative().equals(vlanId);
+ }
+
+ /**
* Build the DHCP discover/request packet with gateway IP(unicast packet).
*
* @param context the packet context
@@ -392,6 +484,12 @@
*/
private Ethernet processDhcpPacketFromClient(PacketContext context,
Ethernet ethernetPacket) {
+ // get dhcp header.
+ Ethernet etherReply = (Ethernet) ethernetPacket.clone();
+ IPv4 ipv4Packet = (IPv4) etherReply.getPayload();
+ UDP udpPacket = (UDP) ipv4Packet.getPayload();
+ DHCP dhcpPacket = (DHCP) udpPacket.getPayload();
+
Ip4Address clientInterfaceIp =
interfaceService.getInterfacesByPort(context.inPacket().receivedFrom())
.stream()
@@ -407,9 +505,10 @@
context.inPacket().receivedFrom());
return null;
}
- Interface serverInterface = getServerInterface();
+ boolean isDirectlyConnected = directlyConnected(dhcpPacket);
+ Interface serverInterface = isDirectlyConnected ? getServerInterface() : getIndirectServerInterface();
if (serverInterface == null) {
- log.warn("Can't get server interface, ignore");
+ log.warn("Can't get {} server interface, ignore", isDirectlyConnected ? "direct" : "indirect");
return null;
}
Ip4Address ipFacingServer = getFirstIpFromInterface(serverInterface);
@@ -426,18 +525,14 @@
context.inPacket().receivedFrom());
return null;
}
- // get dhcp header.
- Ethernet etherReply = (Ethernet) ethernetPacket.clone();
+
etherReply.setSourceMACAddress(macFacingServer);
etherReply.setDestinationMACAddress(dhcpConnectMac);
etherReply.setVlanID(dhcpConnectVlan.toShort());
- IPv4 ipv4Packet = (IPv4) etherReply.getPayload();
ipv4Packet.setSourceAddress(ipFacingServer.toInt());
ipv4Packet.setDestinationAddress(dhcpServerIp.toInt());
- UDP udpPacket = (UDP) ipv4Packet.getPayload();
- DHCP dhcpPacket = (DHCP) udpPacket.getPayload();
- if (directlyConnected(dhcpPacket)) {
+ if (isDirectlyConnected) {
ConnectPoint inPort = context.inPacket().receivedFrom();
VlanId vlanId = VlanId.vlanId(ethernetPacket.getVlanID());
// add connected in port and vlan
@@ -471,17 +566,26 @@
// Sets giaddr to IP address from the Interface which facing to
// DHCP client
dhcpPacket.setGatewayIPAddress(clientInterfaceIp.toInt());
- }
- // replace giaddr if relay agent IP is set
- // FIXME for both direct and indirect case now, should be separated
- if (relayAgentIp != null) {
- dhcpPacket.setGatewayIPAddress(relayAgentIp.toInt());
+ // replace giaddr if relay agent IP is set
+ if (relayAgentIp != null) {
+ dhcpPacket.setGatewayIPAddress(relayAgentIp.toInt());
+ }
+ } else if (indirectDhcpServerIp != null) {
+ // Indirect case, replace destination to indirect dhcp server if exist
+ etherReply.setDestinationMACAddress(indirectDhcpConnectMac);
+ etherReply.setVlanID(indirectDhcpConnectVlan.toShort());
+ ipv4Packet.setDestinationAddress(indirectDhcpServerIp.toInt());
+
+ // replace giaddr if relay agent IP is set
+ if (indirectRelayAgentIp != null) {
+ dhcpPacket.setGatewayIPAddress(relayAgentIp.toInt());
+ }
}
udpPacket.setPayload(dhcpPacket);
- // As a DHCP relay, the source port should be server port(67) instead
- // of client port(68)
+ // As a DHCP relay, the source port should be server port( instead
+ // of client port.
udpPacket.setSourcePort(UDP.DHCP_SERVER_PORT);
udpPacket.setDestinationPort(UDP.DHCP_SERVER_PORT);
ipv4Packet.setPayload(udpPacket);
@@ -535,7 +639,7 @@
Interface outIface = outInterface.get();
ConnectPoint location = outIface.connectPoint();
- VlanId vlanId = getVlanIdFromOption(dhcpPayload);
+ VlanId vlanId = getVlanIdFromRelayAgentOption(dhcpPayload);
if (vlanId == null) {
vlanId = outIface.vlan();
}
@@ -583,7 +687,7 @@
vlanId = clientInterface.vlan();
} else {
// might be multiple vlan in same interface
- vlanId = getVlanIdFromOption(dhcpPayload);
+ vlanId = getVlanIdFromRelayAgentOption(dhcpPayload);
}
if (vlanId == null) {
vlanId = VlanId.NONE;
@@ -642,7 +746,7 @@
* @param dhcpPayload the DHCP payload
* @return VLAN ID from DHCP payload; null if not exists
*/
- private VlanId getVlanIdFromOption(DHCP dhcpPayload) {
+ private VlanId getVlanIdFromRelayAgentOption(DHCP dhcpPayload) {
DhcpRelayAgentOption option = (DhcpRelayAgentOption) dhcpPayload.getOption(OptionCode_CircuitID);
if (option == null) {
return null;
@@ -733,7 +837,7 @@
Interface outIface = outInterface.get();
HostLocation hostLocation = new HostLocation(outIface.connectPoint(), System.currentTimeMillis());
MacAddress macAddress = MacAddress.valueOf(dhcpPayload.getClientHardwareAddress());
- VlanId vlanId = getVlanIdFromOption(dhcpPayload);
+ VlanId vlanId = getVlanIdFromRelayAgentOption(dhcpPayload);
if (vlanId == null) {
vlanId = outIface.vlan();
}
@@ -795,13 +899,17 @@
*
* @param packet the packet
*/
- private void handleDhcpDiscoverAndRequest(Ethernet packet) {
+ private void handleDhcpDiscoverAndRequest(Ethernet packet, DHCP dhcpPayload) {
+ ConnectPoint portToFotward = dhcpServerConnectPoint;
+ if (!directlyConnected(dhcpPayload) && indirectDhcpServerConnectPoint != null) {
+ portToFotward = indirectDhcpServerConnectPoint;
+ }
// send packet to dhcp server connect point.
- if (dhcpServerConnectPoint != null) {
+ if (portToFotward != null) {
TrafficTreatment t = DefaultTrafficTreatment.builder()
- .setOutput(dhcpServerConnectPoint.port()).build();
+ .setOutput(portToFotward.port()).build();
OutboundPacket o = new DefaultOutboundPacket(
- dhcpServerConnectPoint.deviceId(), t, ByteBuffer.wrap(packet.serialize()));
+ portToFotward.deviceId(), t, ByteBuffer.wrap(packet.serialize()));
if (log.isTraceEnabled()) {
log.trace("Relaying packet to dhcp server {}", packet);
}
@@ -815,7 +923,7 @@
/**
* Gets output interface of a dhcp packet.
* If option 82 exists in the dhcp packet and the option was sent by
- * ONOS (gateway address exists in ONOS interfaces), use the connect
+ * ONOS (circuit format is correct), use the connect
* point and vlan id from circuit id; otherwise, find host by destination
* address and use vlan id from sender (dhcp server).
*
@@ -826,31 +934,21 @@
*/
private Optional<Interface> getClientInterface(Ethernet ethPacket, DHCP dhcpPayload) {
VlanId originalPacketVlanId = VlanId.vlanId(ethPacket.getVlanID());
- IpAddress gatewayIpAddress = Ip4Address.valueOf(dhcpPayload.getGatewayIPAddress());
-
- // get all possible interfaces for client
- Set<Interface> clientInterfaces = interfaceService.getInterfacesByIp(gatewayIpAddress);
DhcpRelayAgentOption option = (DhcpRelayAgentOption) dhcpPayload.getOption(OptionCode_CircuitID);
- // Sent by ONOS, and contains circuit id
- if (!clientInterfaces.isEmpty() && option != null) {
- DhcpOption circuitIdSubOption = option.getSubOption(CIRCUIT_ID.getValue());
- try {
- CircuitId circuitId = CircuitId.deserialize(circuitIdSubOption.getData());
- ConnectPoint connectPoint = ConnectPoint.deviceConnectPoint(circuitId.connectPoint());
- VlanId vlanId = circuitId.vlanId();
- return clientInterfaces.stream()
- .filter(iface -> iface.vlanUntagged().equals(vlanId) ||
- iface.vlan().equals(vlanId) ||
- iface.vlanNative().equals(vlanId) ||
- iface.vlanTagged().contains(vlanId))
- .filter(iface -> iface.connectPoint().equals(connectPoint))
- .findFirst();
- } catch (IllegalArgumentException ex) {
- // invalid circuit format, didn't sent by ONOS
- log.debug("Invalid circuit {}, use information from dhcp payload",
- circuitIdSubOption.getData());
- }
+ DhcpOption circuitIdSubOption = option.getSubOption(CIRCUIT_ID.getValue());
+ try {
+ CircuitId circuitId = CircuitId.deserialize(circuitIdSubOption.getData());
+ ConnectPoint connectPoint = ConnectPoint.deviceConnectPoint(circuitId.connectPoint());
+ VlanId vlanId = circuitId.vlanId();
+ return interfaceService.getInterfacesByPort(connectPoint)
+ .stream()
+ .filter(iface -> interfaceContainsVlan(iface, vlanId))
+ .findFirst();
+ } catch (IllegalArgumentException ex) {
+ // invalid circuit format, didn't sent by ONOS
+ log.debug("Invalid circuit {}, use information from dhcp payload",
+ circuitIdSubOption.getData());
}
// Use Vlan Id from DHCP server if DHCP relay circuit id was not
@@ -874,8 +972,7 @@
if (clientConnectPoint != null) {
return interfaceService.getInterfacesByPort(clientConnectPoint)
.stream()
- .filter(iface -> iface.vlan().equals(originalPacketVlanId) ||
- iface.vlanUntagged().equals(originalPacketVlanId))
+ .filter(iface -> interfaceContainsVlan(iface, originalPacketVlanId))
.findFirst();
}
return Optional.empty();
@@ -941,16 +1038,12 @@
* @param host the host
*/
private void hostMoved(Host host) {
- if (this.dhcpServerConnectPoint == null) {
- return;
- }
if (this.dhcpGatewayIp != null) {
if (host.ipAddresses().contains(this.dhcpGatewayIp) &&
!host.locations().contains(this.dhcpServerConnectPoint)) {
this.dhcpConnectMac = null;
this.dhcpConnectVlan = null;
}
- return;
}
if (this.dhcpServerIp != null) {
if (host.ipAddresses().contains(this.dhcpServerIp) &&
@@ -959,6 +1052,20 @@
this.dhcpConnectVlan = null;
}
}
+ if (this.indirectDhcpGatewayIp != null) {
+ if (host.ipAddresses().contains(this.indirectDhcpGatewayIp) &&
+ !host.locations().contains(this.indirectDhcpServerConnectPoint)) {
+ this.indirectDhcpConnectMac = null;
+ this.indirectDhcpConnectVlan = null;
+ }
+ }
+ if (this.indirectDhcpServerIp != null) {
+ if (host.ipAddresses().contains(this.indirectDhcpServerIp) &&
+ !host.locations().contains(this.indirectDhcpServerConnectPoint)) {
+ this.indirectDhcpConnectMac = null;
+ this.indirectDhcpConnectVlan = null;
+ }
+ }
}
/**
@@ -973,7 +1080,6 @@
this.dhcpConnectMac = host.mac();
this.dhcpConnectVlan = host.vlan();
}
- return;
}
if (this.dhcpServerIp != null) {
if (host.ipAddresses().contains(this.dhcpServerIp)) {
@@ -981,6 +1087,18 @@
this.dhcpConnectVlan = host.vlan();
}
}
+ if (this.indirectDhcpGatewayIp != null) {
+ if (host.ipAddresses().contains(this.indirectDhcpGatewayIp)) {
+ this.indirectDhcpConnectMac = host.mac();
+ this.indirectDhcpConnectVlan = host.vlan();
+ }
+ }
+ if (this.indirectDhcpServerIp != null) {
+ if (host.ipAddresses().contains(this.indirectDhcpServerIp)) {
+ this.indirectDhcpConnectMac = host.mac();
+ this.indirectDhcpConnectVlan = host.vlan();
+ }
+ }
}
/**
@@ -995,7 +1113,6 @@
this.dhcpConnectMac = null;
this.dhcpConnectVlan = null;
}
- return;
}
if (this.dhcpServerIp != null) {
if (host.ipAddresses().contains(this.dhcpServerIp)) {
@@ -1003,5 +1120,17 @@
this.dhcpConnectVlan = null;
}
}
+ if (this.indirectDhcpGatewayIp != null) {
+ if (host.ipAddresses().contains(this.indirectDhcpGatewayIp)) {
+ this.indirectDhcpConnectMac = null;
+ this.indirectDhcpConnectVlan = null;
+ }
+ }
+ if (this.indirectDhcpServerIp != null) {
+ if (host.ipAddresses().contains(this.indirectDhcpServerIp)) {
+ this.indirectDhcpConnectMac = null;
+ this.indirectDhcpConnectVlan = null;
+ }
+ }
}
}
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayManager.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayManager.java
index 99b8afb..1b50297 100644
--- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayManager.java
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelayManager.java
@@ -17,12 +17,17 @@
import java.nio.ByteBuffer;
import java.util.Collection;
+import java.util.Collections;
import java.util.Dictionary;
+import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Multimap;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
@@ -38,6 +43,7 @@
import org.onlab.packet.IPv6;
import org.onlab.packet.Ethernet;
import org.onlab.packet.IPv4;
+import org.onlab.packet.Ip4Address;
import org.onlab.packet.MacAddress;
import org.onlab.packet.TpPort;
import org.onlab.packet.UDP;
@@ -49,10 +55,22 @@
import org.onosproject.dhcprelay.api.DhcpHandler;
import org.onosproject.dhcprelay.api.DhcpRelayService;
import org.onosproject.dhcprelay.config.DefaultDhcpRelayConfig;
+import org.onosproject.dhcprelay.config.IgnoreDhcpConfig;
import org.onosproject.dhcprelay.config.IndirectDhcpRelayConfig;
import org.onosproject.dhcprelay.store.DhcpRecord;
import org.onosproject.dhcprelay.store.DhcpRelayStore;
+import org.onosproject.net.DeviceId;
+import org.onosproject.dhcprelay.config.DhcpServerConfig;
+import org.onosproject.net.Host;
import org.onosproject.net.config.Config;
+import org.onosproject.net.flow.criteria.Criterion;
+import org.onosproject.net.flow.criteria.UdpPortCriterion;
+import org.onosproject.net.flowobjective.DefaultForwardingObjective;
+import org.onosproject.net.flowobjective.FlowObjectiveService;
+import org.onosproject.net.flowobjective.ForwardingObjective;
+import org.onosproject.net.flowobjective.Objective;
+import org.onosproject.net.flowobjective.ObjectiveContext;
+import org.onosproject.net.flowobjective.ObjectiveError;
import org.onosproject.net.intf.Interface;
import org.onosproject.net.intf.InterfaceService;
import org.onosproject.net.ConnectPoint;
@@ -92,6 +110,36 @@
"org.onosproject.provider.host.impl.HostLocationProvider";
public static final String ROUTE_STORE_IMPL =
"org.onosproject.routeservice.store.RouteStoreImpl";
+ private static final TrafficSelector DHCP_SERVER_SELECTOR = DefaultTrafficSelector.builder()
+ .matchEthType(Ethernet.TYPE_IPV4)
+ .matchIPProtocol(IPv4.PROTOCOL_UDP)
+ .matchUdpDst(TpPort.tpPort(UDP.DHCP_SERVER_PORT))
+ .build();
+ private static final TrafficSelector DHCP_CLIENT_SELECTOR = DefaultTrafficSelector.builder()
+ .matchEthType(Ethernet.TYPE_IPV4)
+ .matchIPProtocol(IPv4.PROTOCOL_UDP)
+ .matchUdpDst(TpPort.tpPort(UDP.DHCP_CLIENT_PORT))
+ .build();
+ private static final TrafficSelector DHCP6_SERVER_SELECTOR = DefaultTrafficSelector.builder()
+ .matchEthType(Ethernet.TYPE_IPV6)
+ .matchIPProtocol(IPv4.PROTOCOL_UDP)
+ .matchUdpDst(TpPort.tpPort(UDP.DHCP_V6_SERVER_PORT))
+ .build();
+ private static final TrafficSelector DHCP6_CLIENT_SELECTOR = DefaultTrafficSelector.builder()
+ .matchEthType(Ethernet.TYPE_IPV6)
+ .matchIPProtocol(IPv4.PROTOCOL_UDP)
+ .matchUdpDst(TpPort.tpPort(UDP.DHCP_V6_CLIENT_PORT))
+ .build();
+ static final List<TrafficSelector> DHCP_SELECTORS = ImmutableList.of(
+ DHCP_SERVER_SELECTOR,
+ DHCP_CLIENT_SELECTOR,
+ DHCP6_SERVER_SELECTOR,
+ DHCP6_CLIENT_SELECTOR
+ );
+ private static final TrafficSelector ARP_SELECTOR = DefaultTrafficSelector.builder()
+ .matchEthType(Ethernet.TYPE_ARP)
+ .build();
+ private static final int IGNORE_CONTROL_PRIORITY = PacketPriority.CONTROL.priorityValue() + 1000;
private final Logger log = LoggerFactory.getLogger(getClass());
private final InternalConfigListener cfgListener = new InternalConfigListener();
@@ -113,6 +161,15 @@
public IndirectDhcpRelayConfig createConfig() {
return new IndirectDhcpRelayConfig();
}
+ },
+ new ConfigFactory<ApplicationId, IgnoreDhcpConfig>(APP_SUBJECT_FACTORY,
+ IgnoreDhcpConfig.class,
+ IgnoreDhcpConfig.KEY,
+ true) {
+ @Override
+ public IgnoreDhcpConfig createConfig() {
+ return new IgnoreDhcpConfig();
+ }
}
);
@@ -137,6 +194,9 @@
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected ComponentConfigService compCfgService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected FlowObjectiveService flowObjectiveService;
+
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY,
target = "(version=4)")
protected DhcpHandler v4Handler;
@@ -149,6 +209,7 @@
label = "Enable Address resolution protocol")
protected boolean arpEnabled = true;
+ protected Multimap<DeviceId, VlanId> ignoredVlans = HashMultimap.create();
private DhcpRelayPacketProcessor dhcpRelayPacketProcessor = new DhcpRelayPacketProcessor();
private ApplicationId appId;
@@ -218,14 +279,18 @@
cfgService.getConfig(appId, DefaultDhcpRelayConfig.class);
IndirectDhcpRelayConfig indirectConfig =
cfgService.getConfig(appId, IndirectDhcpRelayConfig.class);
+ IgnoreDhcpConfig ignoreDhcpConfig =
+ cfgService.getConfig(appId, IgnoreDhcpConfig.class);
if (defaultConfig != null) {
updateConfig(defaultConfig);
}
-
if (indirectConfig != null) {
updateConfig(indirectConfig);
}
+ if (ignoreDhcpConfig != null) {
+ updateConfig(ignoreDhcpConfig);
+ }
}
/**
@@ -233,12 +298,7 @@
*
* @param config the configuration ot update
*/
- private void updateConfig(Config config) {
- if (config == null) {
- // Ignore if config is not present
- return;
- }
-
+ protected void updateConfig(Config config) {
if (config instanceof IndirectDhcpRelayConfig) {
IndirectDhcpRelayConfig indirectConfig = (IndirectDhcpRelayConfig) config;
v4Handler.setIndirectDhcpServerConfigs(indirectConfig.dhcpServerConfigs());
@@ -248,58 +308,141 @@
v4Handler.setDefaultDhcpServerConfigs(defaultConfig.dhcpServerConfigs());
v6Handler.setDefaultDhcpServerConfigs(defaultConfig.dhcpServerConfigs());
}
+ if (config instanceof IgnoreDhcpConfig) {
+ addIgnoreVlanRules((IgnoreDhcpConfig) config);
+ }
+ }
+
+ protected void removeConfig(Config config) {
+ if (config instanceof IndirectDhcpRelayConfig) {
+ v4Handler.setIndirectDhcpServerConfigs(Collections.emptyList());
+ v6Handler.setIndirectDhcpServerConfigs(Collections.emptyList());
+ } else if (config instanceof DefaultDhcpRelayConfig) {
+ v4Handler.setDefaultDhcpServerConfigs(Collections.emptyList());
+ v6Handler.setDefaultDhcpServerConfigs(Collections.emptyList());
+ }
+ if (config instanceof IgnoreDhcpConfig) {
+ ignoredVlans.forEach(this::removeIgnoreVlanRule);
+ ignoredVlans.clear();
+ }
+ }
+
+ private void addIgnoreVlanRules(IgnoreDhcpConfig config) {
+ config.ignoredVlans().forEach((deviceId, vlanId) -> {
+ if (ignoredVlans.get(deviceId).contains(vlanId)) {
+ // don't need to process if it already ignored
+ return;
+ }
+ installIgnoreVlanRule(deviceId, vlanId);
+ ignoredVlans.put(deviceId, vlanId);
+ });
+
+ Multimap<DeviceId, VlanId> removedVlans = HashMultimap.create();
+ ignoredVlans.forEach((deviceId, vlanId) -> {
+ if (!config.ignoredVlans().get(deviceId).contains(vlanId)) {
+ // not contains in new config, remove it
+ removeIgnoreVlanRule(deviceId, vlanId);
+ removedVlans.put(deviceId, vlanId);
+
+ }
+ });
+ removedVlans.forEach(ignoredVlans::remove);
+ }
+
+ private void installIgnoreVlanRule(DeviceId deviceId, VlanId vlanId) {
+ TrafficTreatment dropTreatment = DefaultTrafficTreatment.emptyTreatment();
+ dropTreatment.clearedDeferred();
+ DHCP_SELECTORS.forEach(trafficSelector -> {
+ UdpPortCriterion udpDst = (UdpPortCriterion) trafficSelector.getCriterion(Criterion.Type.UDP_DST);
+ TrafficSelector selector = DefaultTrafficSelector.builder(trafficSelector)
+ .matchVlanId(vlanId)
+ .build();
+
+ ForwardingObjective fwd = DefaultForwardingObjective.builder()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withSelector(selector)
+ .withPriority(IGNORE_CONTROL_PRIORITY)
+ .withTreatment(dropTreatment)
+ .fromApp(appId)
+ .add(new ObjectiveContext() {
+ @Override
+ public void onSuccess(Objective objective) {
+ log.info("Vlan id {} from device {} ignored (UDP port {})",
+ vlanId, deviceId, udpDst.udpPort().toInt());
+ }
+
+ @Override
+ public void onError(Objective objective, ObjectiveError error) {
+ log.warn("Can't ignore vlan id {} from device {} due to {}",
+ vlanId, deviceId, error);
+ }
+ });
+ flowObjectiveService.apply(deviceId, fwd);
+ });
+ }
+
+ private void removeIgnoreVlanRule(DeviceId deviceId, VlanId vlanId) {
+ TrafficTreatment dropTreatment = DefaultTrafficTreatment.emptyTreatment();
+ dropTreatment.clearedDeferred();
+ DHCP_SELECTORS.forEach(trafficSelector -> {
+ UdpPortCriterion udpDst = (UdpPortCriterion) trafficSelector.getCriterion(Criterion.Type.UDP_DST);
+ TrafficSelector selector = DefaultTrafficSelector.builder(trafficSelector)
+ .matchVlanId(vlanId)
+ .build();
+
+ ForwardingObjective fwd = DefaultForwardingObjective.builder()
+ .withFlag(ForwardingObjective.Flag.VERSATILE)
+ .withSelector(selector)
+ .withPriority(IGNORE_CONTROL_PRIORITY)
+ .withTreatment(dropTreatment)
+ .fromApp(appId)
+ .remove(new ObjectiveContext() {
+ @Override
+ public void onSuccess(Objective objective) {
+ log.info("Vlan id {} from device {} ignore rule removed (UDP port {})",
+ vlanId, deviceId, udpDst.udpPort().toInt());
+ }
+
+ @Override
+ public void onError(Objective objective, ObjectiveError error) {
+ log.warn("Can't remove ignore rule of vlan id {} from device {} due to {}",
+ vlanId, deviceId, error);
+ }
+ });
+ flowObjectiveService.apply(deviceId, fwd);
+ });
}
/**
* Request DHCP packet in via PacketService.
*/
private void requestDhcpPackets() {
- TrafficSelector.Builder selectorServer = DefaultTrafficSelector.builder()
- .matchEthType(Ethernet.TYPE_IPV4)
- .matchIPProtocol(IPv4.PROTOCOL_UDP)
- .matchUdpSrc(TpPort.tpPort(UDP.DHCP_SERVER_PORT));
- packetService.requestPackets(selectorServer.build(), PacketPriority.CONTROL, appId);
-
- TrafficSelector.Builder selectorClient = DefaultTrafficSelector.builder()
- .matchEthType(Ethernet.TYPE_IPV4)
- .matchIPProtocol(IPv4.PROTOCOL_UDP)
- .matchUdpSrc(TpPort.tpPort(UDP.DHCP_CLIENT_PORT));
- packetService.requestPackets(selectorClient.build(), PacketPriority.CONTROL, appId);
+ DHCP_SELECTORS.forEach(trafficSelector -> {
+ packetService.requestPackets(trafficSelector, PacketPriority.CONTROL, appId);
+ });
}
/**
* Cancel requested DHCP packets in via packet service.
*/
private void cancelDhcpPackets() {
- TrafficSelector.Builder selectorServer = DefaultTrafficSelector.builder()
- .matchEthType(Ethernet.TYPE_IPV4)
- .matchIPProtocol(IPv4.PROTOCOL_UDP)
- .matchUdpSrc(TpPort.tpPort(UDP.DHCP_SERVER_PORT));
- packetService.cancelPackets(selectorServer.build(), PacketPriority.CONTROL, appId);
-
- TrafficSelector.Builder selectorClient = DefaultTrafficSelector.builder()
- .matchEthType(Ethernet.TYPE_IPV4)
- .matchIPProtocol(IPv4.PROTOCOL_UDP)
- .matchUdpSrc(TpPort.tpPort(UDP.DHCP_CLIENT_PORT));
- packetService.cancelPackets(selectorClient.build(), PacketPriority.CONTROL, appId);
+ DHCP_SELECTORS.forEach(trafficSelector -> {
+ packetService.cancelPackets(trafficSelector, PacketPriority.CONTROL, appId);
+ });
}
/**
* Request ARP packet in via PacketService.
*/
private void requestArpPackets() {
- TrafficSelector.Builder selectorArpServer = DefaultTrafficSelector.builder()
- .matchEthType(Ethernet.TYPE_ARP);
- packetService.requestPackets(selectorArpServer.build(), PacketPriority.CONTROL, appId);
+ packetService.requestPackets(ARP_SELECTOR, PacketPriority.CONTROL, appId);
}
/**
* Cancel requested ARP packets in via packet service.
*/
private void cancelArpPackets() {
- TrafficSelector.Builder selectorArpServer = DefaultTrafficSelector.builder()
- .matchEthType(Ethernet.TYPE_ARP);
- packetService.cancelPackets(selectorArpServer.build(), PacketPriority.CONTROL, appId);
+ packetService.cancelPackets(ARP_SELECTOR, PacketPriority.CONTROL, appId);
}
@Override
@@ -314,7 +457,14 @@
@Override
public Optional<MacAddress> getDhcpServerMacAddress() {
- return v4Handler.getDhcpConnectMac();
+ // TODO: depreated it
+ DefaultDhcpRelayConfig config = cfgService.getConfig(appId, DefaultDhcpRelayConfig.class);
+ DhcpServerConfig serverConfig = config.dhcpServerConfigs().get(0);
+ Ip4Address serverip = serverConfig.getDhcpServerIp4().get();
+ return hostService.getHostsByIp(serverip)
+ .stream()
+ .map(Host::mac)
+ .findFirst();
}
/**
@@ -449,20 +599,25 @@
private class InternalConfigListener implements NetworkConfigListener {
@Override
public void event(NetworkConfigEvent event) {
- if (event.type() != NetworkConfigEvent.Type.CONFIG_ADDED &&
- event.type() != NetworkConfigEvent.Type.CONFIG_UPDATED) {
- // Ignore unhandled event type
- return;
+ switch (event.type()) {
+ case CONFIG_UPDATED:
+ case CONFIG_ADDED:
+ event.config().ifPresent(config -> {
+ updateConfig(config);
+ log.info("{} updated", config.getClass().getSimpleName());
+ });
+ break;
+ case CONFIG_REMOVED:
+ event.prevConfig().ifPresent(config -> {
+ removeConfig(config);
+ log.info("{} removed", config.getClass().getSimpleName());
+ });
+ break;
+ default:
+ log.warn("Unsupported event type {}", event.type());
+ break;
}
- if (!event.configClass().equals(DefaultDhcpRelayConfig.class) &&
- !event.configClass().equals(IndirectDhcpRelayConfig.class)) {
- // Ignore unhandled config type
- return;
- }
- event.config().ifPresent(config -> {
- updateConfig(config);
- log.info("Reconfigured");
- });
+
}
}
}
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/api/DhcpHandler.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/api/DhcpHandler.java
index a821be5..7f5dd46 100644
--- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/api/DhcpHandler.java
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/api/DhcpHandler.java
@@ -46,6 +46,7 @@
* @return IP address of DHCP server; empty value if not exist
* @deprecated 1.12 get the address from config service
*/
+ @Deprecated
Optional<IpAddress> getDhcpServerIp();
/**
@@ -61,7 +62,7 @@
* Gets DHCP connect Mac address.
*
* @return the connect Mac address of server or gateway
- * @deprecated 1.12 get host mac from host server
+ * @deprecated 1.12 get host mac from host service
*/
@Deprecated
Optional<MacAddress> getDhcpConnectMac();
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/cli/DhcpRelayCommand.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/cli/DhcpRelayCommand.java
index 5a4ecde..d4ea1d8 100644
--- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/cli/DhcpRelayCommand.java
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/cli/DhcpRelayCommand.java
@@ -66,6 +66,7 @@
@Override
protected void execute() {
+ // TODO: add indirect config
DefaultDhcpRelayConfig cfg = CFG_SERVICE.getConfig(APP_ID, DefaultDhcpRelayConfig.class);
if (cfg == null || cfg.dhcpServerConfigs().size() == 0) {
print(MISSING_SERVER_CFG);
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/config/IgnoreDhcpConfig.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/config/IgnoreDhcpConfig.java
new file mode 100644
index 0000000..b4b8adb
--- /dev/null
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/config/IgnoreDhcpConfig.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.
+ */
+
+package org.onosproject.dhcprelay.config;
+
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Multimap;
+import org.onlab.packet.VlanId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.config.Config;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+public class IgnoreDhcpConfig extends Config<ApplicationId> {
+ public static final String KEY = "ignoreDhcp";
+ private static final String DEVICE_ID = "deviceId";
+ private static final String VLAN_ID = "vlan";
+
+ @Override
+ public boolean isValid() {
+ AtomicBoolean valid = new AtomicBoolean(true);
+ if (array == null) {
+ return false;
+ }
+ array.forEach(node -> {
+ valid.compareAndSet(true, node.has(DEVICE_ID) && node.has(VLAN_ID));
+ });
+ return valid.get();
+ }
+
+ public Multimap<DeviceId, VlanId> ignoredVlans() {
+ Multimap<DeviceId, VlanId> ignored = ArrayListMultimap.create();
+
+ array.forEach(node -> {
+ DeviceId deviceId = DeviceId.deviceId(node.get(DEVICE_ID).asText());
+ VlanId vlanId = VlanId.vlanId((short) node.get(VLAN_ID).asInt());
+ ignored.put(deviceId, vlanId);
+ });
+
+ return ignored;
+ }
+}
diff --git a/apps/dhcprelay/src/test/java/org/onosproject/dhcprelay/DhcpRelayManagerTest.java b/apps/dhcprelay/src/test/java/org/onosproject/dhcprelay/DhcpRelayManagerTest.java
index 45cfa23..4494ddb 100644
--- a/apps/dhcprelay/src/test/java/org/onosproject/dhcprelay/DhcpRelayManagerTest.java
+++ b/apps/dhcprelay/src/test/java/org/onosproject/dhcprelay/DhcpRelayManagerTest.java
@@ -15,12 +15,17 @@
*/
package org.onosproject.dhcprelay;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
+import com.google.common.io.Resources;
import org.apache.commons.io.Charsets;
+import org.easymock.Capture;
+import org.easymock.CaptureType;
import org.easymock.EasyMock;
import org.junit.After;
import org.junit.Before;
@@ -45,12 +50,22 @@
import org.onosproject.dhcprelay.api.DhcpHandler;
import org.onosproject.dhcprelay.config.DefaultDhcpRelayConfig;
import org.onosproject.dhcprelay.config.DhcpServerConfig;
+import org.onosproject.dhcprelay.config.IgnoreDhcpConfig;
import org.onosproject.dhcprelay.config.IndirectDhcpRelayConfig;
import org.onosproject.dhcprelay.store.DhcpRecord;
import org.onosproject.dhcprelay.store.DhcpRelayStore;
import org.onosproject.dhcprelay.store.DhcpRelayStoreEvent;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flowobjective.FlowObjectiveService;
+import org.onosproject.net.flowobjective.ForwardingObjective;
+import org.onosproject.net.flowobjective.Objective;
import org.onosproject.net.intf.Interface;
import org.onosproject.net.intf.InterfaceServiceAdapter;
+import org.onosproject.net.packet.PacketPriority;
import org.onosproject.routeservice.Route;
import org.onosproject.routeservice.RouteStoreAdapter;
import org.onosproject.net.ConnectPoint;
@@ -86,8 +101,12 @@
import static org.easymock.EasyMock.*;
import static org.junit.Assert.*;
+import static org.onosproject.dhcprelay.DhcpRelayManager.DHCP_RELAY_APP;
public class DhcpRelayManagerTest {
+ private static final String CONFIG_FILE_PATH = "dhcp-relay.json";
+ private static final DeviceId DEV_1_ID = DeviceId.deviceId("of:0000000000000001");
+ private static final DeviceId DEV_2_ID = DeviceId.deviceId("of:0000000000000002");
// Ip address for interfaces
private static final InterfaceIpAddress INTERFACE_IP = InterfaceIpAddress.valueOf("10.0.3.254/32");
private static final List<InterfaceIpAddress> INTERFACE_IPS = ImmutableList.of(INTERFACE_IP);
@@ -165,6 +184,8 @@
SERVER_INTERFACE
);
private static final String NON_ONOS_CID = "Non-ONOS circuit ID";
+ private static final VlanId IGNORED_VLAN = VlanId.vlanId("100");
+ private static final int IGNORE_CONTROL_PRIORITY = PacketPriority.CONTROL.priorityValue() + 1000;
private DhcpRelayManager manager;
private MockPacketService packetService;
@@ -204,6 +225,7 @@
manager.dhcpRelayStore = mockDhcpRelayStore;
manager.interfaceService = new MockInterfaceService();
+ manager.flowObjectiveService = EasyMock.niceMock(FlowObjectiveService.class);
Dhcp4HandlerImpl v4Handler = new Dhcp4HandlerImpl();
v4Handler.dhcpRelayStore = mockDhcpRelayStore;
@@ -307,6 +329,8 @@
public void testWithRelayAgentConfig() throws DeserializationException {
manager.v4Handler
.setDefaultDhcpServerConfigs(ImmutableList.of(new MockDhcpServerConfig(RELAY_AGENT_IP)));
+ manager.v4Handler
+ .setIndirectDhcpServerConfigs(ImmutableList.of(new MockDhcpServerConfig(RELAY_AGENT_IP)));
packetService.processPacket(new TestDhcpRequestPacketContext(CLIENT2_MAC,
CLIENT2_VLAN,
CLIENT2_CP,
@@ -333,6 +357,95 @@
assertArrayEquals(arp.getSenderHardwareAddress(), CLIENT_INTERFACE.mac().toBytes());
}
+ /**
+ * Ignores specific vlans from specific devices if config.
+ *
+ * @throws Exception the exception from this test
+ */
+ @Test
+ public void testIgnoreVlan() throws Exception {
+ ObjectMapper om = new ObjectMapper();
+ JsonNode json = om.readTree(Resources.getResource(CONFIG_FILE_PATH));
+ IgnoreDhcpConfig config = new IgnoreDhcpConfig();
+ json = json.path("apps").path(DHCP_RELAY_APP).path(IgnoreDhcpConfig.KEY);
+ config.init(APP_ID, IgnoreDhcpConfig.KEY, json, om, null);
+
+ Capture<Objective> capturedFromDev1 = newCapture(CaptureType.ALL);
+ manager.flowObjectiveService.apply(eq(DEV_1_ID), capture(capturedFromDev1));
+ expectLastCall().times(2);
+ Capture<Objective> capturedFromDev2 = newCapture(CaptureType.ALL);
+ manager.flowObjectiveService.apply(eq(DEV_2_ID), capture(capturedFromDev2));
+ expectLastCall().times(2);
+ replay(manager.flowObjectiveService);
+ manager.updateConfig(config);
+ verify(manager.flowObjectiveService);
+
+ List<Objective> objectivesFromDev1 = capturedFromDev1.getValues();
+ List<Objective> objectivesFromDev2 = capturedFromDev2.getValues();
+
+ assertTrue(objectivesFromDev1.containsAll(objectivesFromDev2));
+ assertTrue(objectivesFromDev2.containsAll(objectivesFromDev1));
+ TrafficTreatment dropTreatment = DefaultTrafficTreatment.emptyTreatment();
+ dropTreatment.clearedDeferred();
+
+ for (int index = 0; index < objectivesFromDev1.size(); index++) {
+ TrafficSelector selector =
+ DefaultTrafficSelector.builder(DhcpRelayManager.DHCP_SELECTORS.get(index))
+ .matchVlanId(IGNORED_VLAN)
+ .build();
+ ForwardingObjective fwd = (ForwardingObjective) objectivesFromDev1.get(index);
+ assertEquals(selector, fwd.selector());
+ assertEquals(dropTreatment, fwd.treatment());
+ assertEquals(IGNORE_CONTROL_PRIORITY, fwd.priority());
+ assertEquals(ForwardingObjective.Flag.VERSATILE, fwd.flag());
+ assertEquals(Objective.Operation.ADD, fwd.op());
+ }
+
+ assertEquals(2, manager.ignoredVlans.size());
+ }
+
+ /**
+ * "IgnoreVlan" policy should be removed when the config removed.
+ */
+ @Test
+ public void testRemoveIgnoreVlan() {
+ manager.ignoredVlans.put(DEV_1_ID, IGNORED_VLAN);
+ manager.ignoredVlans.put(DEV_2_ID, IGNORED_VLAN);
+ IgnoreDhcpConfig config = new IgnoreDhcpConfig();
+
+ Capture<Objective> capturedFromDev1 = newCapture(CaptureType.ALL);
+ manager.flowObjectiveService.apply(eq(DEV_1_ID), capture(capturedFromDev1));
+ expectLastCall().times(2);
+ Capture<Objective> capturedFromDev2 = newCapture(CaptureType.ALL);
+ manager.flowObjectiveService.apply(eq(DEV_2_ID), capture(capturedFromDev2));
+ expectLastCall().times(2);
+ replay(manager.flowObjectiveService);
+ manager.removeConfig(config);
+ verify(manager.flowObjectiveService);
+
+ List<Objective> objectivesFromDev1 = capturedFromDev1.getValues();
+ List<Objective> objectivesFromDev2 = capturedFromDev2.getValues();
+
+ assertTrue(objectivesFromDev1.containsAll(objectivesFromDev2));
+ assertTrue(objectivesFromDev2.containsAll(objectivesFromDev1));
+ TrafficTreatment dropTreatment = DefaultTrafficTreatment.emptyTreatment();
+ dropTreatment.clearedDeferred();
+
+ for (int index = 0; index < objectivesFromDev1.size(); index++) {
+ TrafficSelector selector =
+ DefaultTrafficSelector.builder(DhcpRelayManager.DHCP_SELECTORS.get(index))
+ .matchVlanId(IGNORED_VLAN)
+ .build();
+ ForwardingObjective fwd = (ForwardingObjective) objectivesFromDev1.get(index);
+ assertEquals(selector, fwd.selector());
+ assertEquals(dropTreatment, fwd.treatment());
+ assertEquals(IGNORE_CONTROL_PRIORITY, fwd.priority());
+ assertEquals(ForwardingObjective.Flag.VERSATILE, fwd.flag());
+ assertEquals(Objective.Operation.REMOVE, fwd.op());
+ }
+ assertEquals(0, manager.ignoredVlans.size());
+ }
+
private static class MockDefaultDhcpRelayConfig extends DefaultDhcpRelayConfig {
@Override
public boolean isValid() {
diff --git a/apps/dhcprelay/src/test/java/org/onosproject/dhcprelay/config/DhcpRelayConfigTest.java b/apps/dhcprelay/src/test/java/org/onosproject/dhcprelay/config/DhcpRelayConfigTest.java
index 4160e06..c743247 100644
--- a/apps/dhcprelay/src/test/java/org/onosproject/dhcprelay/config/DhcpRelayConfigTest.java
+++ b/apps/dhcprelay/src/test/java/org/onosproject/dhcprelay/config/DhcpRelayConfigTest.java
@@ -27,7 +27,6 @@
import org.onosproject.core.ApplicationId;
import org.onosproject.net.ConnectPoint;
-
import java.io.IOException;
import static org.junit.Assert.*;
@@ -45,7 +44,6 @@
private static final Ip4Address DEFAULT_GATEWAY_IP = Ip4Address.valueOf("192.168.10.254");
private static final Ip6Address DEFAULT_SERVER_IP_V6 = Ip6Address.valueOf("2000::200:1");
private static final Ip6Address DEFAULT_GATEWAY_IP_V6 = Ip6Address.valueOf("1000::100:1");
-
private static final ConnectPoint INDIRECT_CONNECT_POINT = ConnectPoint.deviceConnectPoint("of:0000000000000002/3");
private static final Ip4Address INDIRECT_SERVER_IP = Ip4Address.valueOf("172.168.10.3");
diff --git a/apps/dhcprelay/src/test/java/org/onosproject/dhcprelay/config/IgnoreDhcpConfigTest.java b/apps/dhcprelay/src/test/java/org/onosproject/dhcprelay/config/IgnoreDhcpConfigTest.java
new file mode 100644
index 0000000..3712c06
--- /dev/null
+++ b/apps/dhcprelay/src/test/java/org/onosproject/dhcprelay/config/IgnoreDhcpConfigTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.
+ */
+
+package org.onosproject.dhcprelay.config;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.io.Resources;
+import org.junit.Test;
+import org.onlab.packet.VlanId;
+import org.onosproject.TestApplicationId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.DeviceId;
+
+import java.io.IOException;
+import java.util.Collection;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.onosproject.dhcprelay.DhcpRelayManager.DHCP_RELAY_APP;
+
+public class IgnoreDhcpConfigTest {
+ private static final String CONFIG_FILE_PATH = "dhcp-relay.json";
+ private static final ApplicationId APP_ID = new TestApplicationId("DhcpRelayTest");
+ private static final DeviceId DEV_1_ID = DeviceId.deviceId("of:0000000000000001");
+ private static final DeviceId DEV_2_ID = DeviceId.deviceId("of:0000000000000002");
+ private static final VlanId IGNORED_VLAN = VlanId.vlanId("100");
+ @Test
+ public void testIgnoredDhcpConfig() throws IOException {
+ ObjectMapper om = new ObjectMapper();
+ JsonNode json = om.readTree(Resources.getResource(CONFIG_FILE_PATH));
+ IgnoreDhcpConfig config = new IgnoreDhcpConfig();
+ json = json.path("apps").path(DHCP_RELAY_APP).path(IgnoreDhcpConfig.KEY);
+ config.init(APP_ID, IgnoreDhcpConfig.KEY, json, om, null);
+
+ assertEquals(2, config.ignoredVlans().size());
+ Collection<VlanId> vlanForDev1 = config.ignoredVlans().get(DEV_1_ID);
+ Collection<VlanId> vlanForDev2 = config.ignoredVlans().get(DEV_2_ID);
+
+ assertEquals(1, vlanForDev1.size());
+ assertEquals(1, vlanForDev2.size());
+
+ assertTrue(vlanForDev1.contains(IGNORED_VLAN));
+ assertTrue(vlanForDev2.contains(IGNORED_VLAN));
+ }
+}
diff --git a/apps/dhcprelay/src/test/resources/dhcp-relay.json b/apps/dhcprelay/src/test/resources/dhcp-relay.json
index dc724ee..e77d8a7 100644
--- a/apps/dhcprelay/src/test/resources/dhcp-relay.json
+++ b/apps/dhcprelay/src/test/resources/dhcp-relay.json
@@ -15,6 +15,10 @@
"serverIps": ["172.168.10.3"],
"relayAgentIps": ["10.0.1.1"]
}
+ ],
+ "ignoreDhcp": [
+ {"deviceId": "of:0000000000000001", "vlan": 100},
+ {"deviceId": "of:0000000000000002", "vlan": 100}
]
}
}
diff --git a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeFlowRuleProgrammable.java b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeFlowRuleProgrammable.java
index 515640b..ad9329a 100644
--- a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeFlowRuleProgrammable.java
+++ b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeFlowRuleProgrammable.java
@@ -40,6 +40,7 @@
import java.util.concurrent.ExecutionException;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
+import java.util.stream.Collectors;
import static com.google.common.collect.Lists.newArrayList;
import static org.onosproject.drivers.p4runtime.P4RuntimeFlowRuleProgrammable.Operation.APPLY;
@@ -52,19 +53,25 @@
*/
public class P4RuntimeFlowRuleProgrammable extends AbstractP4RuntimeHandlerBehaviour implements FlowRuleProgrammable {
- // TODO: make this attribute configurable by child drivers (e.g. BMv2 or Tofino)
/*
When updating an existing rule, if true, we issue a DELETE operation before inserting the new one, otherwise we
issue a MODIFY operation. This is useful fore devices that do not support MODIFY operations for table entries.
*/
+ // TODO: make this attribute configurable by child drivers (e.g. BMv2 or Tofino)
private boolean deleteEntryBeforeUpdate = true;
- // TODO: can remove this check as soon as the multi-apply-per-same-flow rule bug is fixed.
/*
If true, we ignore re-installing rules that are already known in the ENTRY_STORE, i.e. same match key and action.
*/
+ // TODO: can remove this check as soon as the multi-apply-per-same-flow rule bug is fixed.
private boolean checkEntryStoreBeforeUpdate = true;
+ /*
+ If true, we avoid querying the device and return the content of the ENTRY_STORE.
+ */
+ // TODO: can remove this check as soon as the BMv2 bug when reading ECMP entries is fixed.
+ private boolean ignoreDeviceWhenGet = true;
+
// Needed to synchronize operations over the same table entry.
private static final ConcurrentMap<P4RuntimeTableEntryReference, Lock> ENTRY_LOCKS = Maps.newConcurrentMap();
@@ -101,6 +108,14 @@
return Collections.emptyList();
}
+ if (ignoreDeviceWhenGet) {
+ return ENTRY_STORE.values().stream()
+ .filter(frWrapper -> frWrapper.rule().deviceId().equals(this.deviceId))
+ .map(frWrapper -> new DefaultFlowEntry(frWrapper.rule(), ADDED, frWrapper.lifeInSeconds(),
+ 0, 0))
+ .collect(Collectors.toList());
+ }
+
ImmutableList.Builder<FlowEntry> resultBuilder = ImmutableList.builder();
List<PiTableEntry> inconsistentEntries = Lists.newArrayList();
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/meter/impl/MeterManager.java b/incubator/net/src/main/java/org/onosproject/incubator/net/meter/impl/MeterManager.java
index bd61a5d..f7418ab 100644
--- a/incubator/net/src/main/java/org/onosproject/incubator/net/meter/impl/MeterManager.java
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/meter/impl/MeterManager.java
@@ -19,6 +19,7 @@
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.Service;
@@ -54,8 +55,12 @@
import java.util.Collection;
import java.util.Map;
+import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static java.util.concurrent.Executors.newFixedThreadPool;
+import static org.onlab.util.Tools.groupedThreads;
import static org.slf4j.LoggerFactory.getLogger;
/**
@@ -68,6 +73,16 @@
implements MeterService, MeterProviderRegistry {
private static final String METERCOUNTERIDENTIFIER = "meter-id-counter-%s";
+ private static final String NUM_THREAD = "numThreads";
+ private static final String WORKER_PATTERN = "installer-%d";
+ private static final String GROUP_THREAD_NAME = "onos/meter";
+
+ private static final int DEFAULT_NUM_THREADS = 4;
+ @Property(name = NUM_THREAD,
+ intValue = DEFAULT_NUM_THREADS,
+ label = "Number of worker threads")
+ private int numThreads = DEFAULT_NUM_THREADS;
+
private final Logger log = getLogger(getClass());
private final MeterStoreDelegate delegate = new InternalMeterStoreDelegate();
@@ -85,6 +100,8 @@
private TriConsumer<MeterRequest, MeterStoreResult, Throwable> onComplete;
+ private ExecutorService executorService;
+
@Activate
public void activate() {
store.setDelegate(delegate);
@@ -104,6 +121,9 @@
});
};
+
+ executorService = newFixedThreadPool(numThreads,
+ groupedThreads(GROUP_THREAD_NAME, WORKER_PATTERN, log));
log.info("Started");
}
@@ -111,6 +131,7 @@
public void deactivate() {
store.unsetDelegate(delegate);
eventDispatcher.removeSink(MeterEvent.class);
+ executorService.shutdown();
log.info("Stopped");
}
@@ -308,21 +329,22 @@
@Override
public void notify(MeterEvent event) {
DeviceId deviceId = event.subject().deviceId();
- MeterProvider p = getProvider(event.subject().deviceId());
switch (event.type()) {
case METER_ADD_REQ:
- p.performMeterOperation(deviceId, new MeterOperation(event.subject(),
- MeterOperation.Type.ADD));
+ executorService.execute(new MeterInstaller(deviceId, event.subject(),
+ MeterOperation.Type.ADD));
break;
case METER_REM_REQ:
- p.performMeterOperation(deviceId, new MeterOperation(event.subject(),
- MeterOperation.Type.REMOVE));
+ executorService.execute(new MeterInstaller(deviceId, event.subject(),
+ MeterOperation.Type.REMOVE));
break;
case METER_ADDED:
log.info("Meter added {}", event.subject());
+ post(new MeterEvent(MeterEvent.Type.METER_ADDED, event.subject()));
break;
case METER_REMOVED:
log.info("Meter removed {}", event.subject());
+ post(new MeterEvent(MeterEvent.Type.METER_REMOVED, event.subject()));
break;
default:
log.warn("Unknown meter event {}", event.type());
@@ -330,5 +352,29 @@
}
}
+ /**
+ * Task that passes the meter down to the provider.
+ */
+ private class MeterInstaller implements Runnable {
+ private final DeviceId deviceId;
+ private final Meter meter;
+ private final MeterOperation.Type op;
+
+ public MeterInstaller(DeviceId deviceId, Meter meter, MeterOperation.Type op) {
+ this.deviceId = checkNotNull(deviceId);
+ this.meter = checkNotNull(meter);
+ this.op = checkNotNull(op);
+ }
+
+ @Override
+ public void run() {
+ MeterProvider p = getProvider(this.deviceId);
+ if (p == null) {
+ log.error("Unable to recover {}'s provider", deviceId);
+ return;
+ }
+ p.performMeterOperation(deviceId, new MeterOperation(meter, op));
+ }
+ }
}
diff --git a/web/gui/src/main/resources/org/onosproject/ui/lion/core/common/Props_ko.properties b/web/gui/src/main/resources/org/onosproject/ui/lion/core/common/Props_ko.properties
index 418807c..1c8eacd 100644
--- a/web/gui/src/main/resources/org/onosproject/ui/lion/core/common/Props_ko.properties
+++ b/web/gui/src/main/resources/org/onosproject/ui/lion/core/common/Props_ko.properties
@@ -21,16 +21,16 @@
hw_version=하드웨어 버전
sw_version=소프트웨어 버전
serial_number=시리얼 번호
-app_id=어플리케이션 아아디
+app_id=애플리케이션 아이디
type=종류
-vendor=벤더
+vendor=제조사
icon=아이콘
title=이름
state=상태
category=카테고리
version=버전
-origin=제조사
+origin=Origin
role=역할
latitude=위도
diff --git a/web/gui/src/main/webapp/app/fw/svg/glyphData.js b/web/gui/src/main/webapp/app/fw/svg/glyphData.js
index 083acbd..386a74c 100644
--- a/web/gui/src/main/webapp/app/fw/svg/glyphData.js
+++ b/web/gui/src/main/webapp/app/fw/svg/glyphData.js
@@ -294,6 +294,9 @@
download: 'M90.3,94.5H19.7V79.2H90.3V94.5Z' +
'm-49.1-79V44H26.2L55,72.3,83.8,44H68.9V15.5H41.1Z',
+ upload: 'M90.3,79.4H19.7V94.6H90.3V79.4Z' +
+ 'M41.1,71.8V43.5H26.2L55,15.4,83.8,43.5H68.9V71.8H41.1Z',
+
// --- Navigation glyphs ------------------------------------
flowTable: tableFrame +
diff --git a/web/gui/src/main/webapp/app/fw/svg/icon.js b/web/gui/src/main/webapp/app/fw/svg/icon.js
index 5dc8a3d..9027960 100644
--- a/web/gui/src/main/webapp/app/fw/svg/icon.js
+++ b/web/gui/src/main/webapp/app/fw/svg/icon.js
@@ -37,6 +37,7 @@
play: 'play',
stop: 'stop',
+ upload: 'upload',
download: 'download',
delta: 'delta',
nonzero: 'nonzero',
diff --git a/web/gui/src/main/webapp/app/view/app/app.html b/web/gui/src/main/webapp/app/view/app/app.html
index 1d6c94a..54a5390 100644
--- a/web/gui/src/main/webapp/app/view/app/app.html
+++ b/web/gui/src/main/webapp/app/view/app/app.html
@@ -19,7 +19,7 @@
file-model="appFile">
</form>
- <div icon icon-size="42" icon-id="plus"
+ <div icon icon-size="42" icon-id="upload"
class="active" trigger-form
tooltip tt-msg="uploadTip">
</div>
diff --git a/web/gui/src/main/webapp/tests/app/fw/svg/glyph-spec.js b/web/gui/src/main/webapp/tests/app/fw/svg/glyph-spec.js
index 0d6e17e..73c1d6c 100644
--- a/web/gui/src/main/webapp/tests/app/fw/svg/glyph-spec.js
+++ b/web/gui/src/main/webapp/tests/app/fw/svg/glyph-spec.js
@@ -21,7 +21,7 @@
describe('factory: fw/svg/glyph.js', function() {
var $log, fs, gs, d3Elem, svg;
- var numBaseGlyphs = 104,
+ var numBaseGlyphs = 105,
vbBird = '352 224 113 112',
vbGlyph = '0 0 110 110',
vbBadge = '0 0 10 10',