| /* |
| * 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.openstacknetworking.impl; |
| |
| import com.google.common.base.Strings; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.Lists; |
| 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.Modified; |
| import org.apache.felix.scr.annotations.Property; |
| import org.apache.felix.scr.annotations.Reference; |
| import org.apache.felix.scr.annotations.ReferenceCardinality; |
| import org.onlab.packet.DHCP; |
| import org.onlab.packet.Ethernet; |
| import org.onlab.packet.IPv4; |
| import org.onlab.packet.Ip4Address; |
| import org.onlab.packet.IpAddress; |
| import org.onlab.packet.IpPrefix; |
| import org.onlab.packet.MacAddress; |
| import org.onlab.packet.TpPort; |
| import org.onlab.packet.UDP; |
| import org.onlab.packet.dhcp.DhcpOption; |
| import org.onlab.util.Tools; |
| import org.onosproject.cfg.ComponentConfigService; |
| import org.onosproject.cluster.ClusterService; |
| import org.onosproject.cluster.LeadershipService; |
| import org.onosproject.cluster.NodeId; |
| import org.onosproject.core.ApplicationId; |
| import org.onosproject.core.CoreService; |
| import org.onosproject.net.ConnectPoint; |
| 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.packet.DefaultOutboundPacket; |
| import org.onosproject.net.packet.PacketContext; |
| import org.onosproject.net.packet.PacketProcessor; |
| import org.onosproject.net.packet.PacketService; |
| import org.onosproject.openstacknetworking.api.Constants; |
| import org.onosproject.openstacknetworking.api.InstancePort; |
| import org.onosproject.openstacknetworking.api.InstancePortService; |
| import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService; |
| import org.onosproject.openstacknetworking.api.OpenstackNetworkService; |
| import org.onosproject.openstacknode.api.OpenstackNode; |
| import org.onosproject.openstacknode.api.OpenstackNodeEvent; |
| import org.onosproject.openstacknode.api.OpenstackNodeListener; |
| import org.onosproject.openstacknode.api.OpenstackNodeService; |
| import org.openstack4j.model.network.HostRoute; |
| import org.openstack4j.model.network.IP; |
| import org.openstack4j.model.network.Network; |
| import org.openstack4j.model.network.Port; |
| import org.openstack4j.model.network.Subnet; |
| import org.osgi.service.component.ComponentContext; |
| import org.slf4j.Logger; |
| |
| import java.nio.ByteBuffer; |
| import java.util.Dictionary; |
| import java.util.List; |
| import java.util.Objects; |
| |
| import static com.google.common.base.Preconditions.checkNotNull; |
| import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_BroadcastAddress; |
| import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_Classless_Static_Route; |
| import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_DHCPServerIp; |
| import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_DomainServer; |
| import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_END; |
| import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_LeaseTime; |
| import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_MessageType; |
| import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_RouterAddress; |
| import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_SubnetMask; |
| import static org.onlab.packet.DHCP.MsgType.DHCPACK; |
| import static org.onlab.packet.DHCP.MsgType.DHCPOFFER; |
| import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_GATEWAY_MAC_STR; |
| import static org.onosproject.openstacknetworking.api.Constants.DHCP_ARP_TABLE; |
| import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_DHCP_RULE; |
| import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE; |
| import static org.slf4j.LoggerFactory.getLogger; |
| |
| /** |
| * Handles DHCP requests for the virtual instances. |
| */ |
| @Component(immediate = true) |
| public class OpenstackSwitchingDhcpHandler { |
| protected final Logger log = getLogger(getClass()); |
| |
| private static final String DHCP_SERVER_MAC = "dhcpServerMac"; |
| private static final Ip4Address DEFAULT_PRIMARY_DNS = Ip4Address.valueOf("8.8.8.8"); |
| private static final Ip4Address DEFAULT_SECONDARY_DNS = Ip4Address.valueOf("8.8.4.4"); |
| private static final byte PACKET_TTL = (byte) 127; |
| // TODO add MTU, static route option codes to ONOS DHCP and remove here |
| private static final byte DHCP_OPTION_MTU = (byte) 26; |
| private static final byte[] DHCP_DATA_LEASE_INFINITE = |
| ByteBuffer.allocate(4).putInt(-1).array(); |
| // we are using 1450 as a default DHCP MTU value |
| private static final int DHCP_DATA_MTU_DEFAULT = 1450; |
| private static final int OCTET_BIT_LENGTH = 8; |
| private static final int V4_BYTE_SIZE = 4; |
| private static final int V4_CIDR_LOWER_BOUND = -1; |
| private static final int V4_CIDR_UPPER_BOUND = 33; |
| private static final int PADDING_SIZE = 4; |
| |
| @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| protected CoreService coreService; |
| |
| @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| protected ComponentConfigService configService; |
| |
| @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| protected PacketService packetService; |
| |
| @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| protected InstancePortService instancePortService; |
| |
| @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| protected OpenstackNetworkService osNetworkService; |
| |
| @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| protected OpenstackNodeService osNodeService; |
| |
| @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| protected OpenstackFlowRuleService osFlowRuleService; |
| |
| @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| protected ClusterService clusterService; |
| |
| @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| protected LeadershipService leadershipService; |
| |
| @Property(name = DHCP_SERVER_MAC, value = DEFAULT_GATEWAY_MAC_STR, |
| label = "Fake MAC address for virtual network subnet gateway") |
| private String dhcpServerMac = DEFAULT_GATEWAY_MAC_STR; |
| |
| private int dhcpDataMtu = DHCP_DATA_MTU_DEFAULT; |
| |
| private final PacketProcessor packetProcessor = new InternalPacketProcessor(); |
| private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener(); |
| |
| private ApplicationId appId; |
| private NodeId localNodeId; |
| |
| @Activate |
| protected void activate() { |
| appId = coreService.registerApplication(Constants.OPENSTACK_NETWORKING_APP_ID); |
| localNodeId = clusterService.getLocalNode().id(); |
| osNodeService.addListener(osNodeListener); |
| configService.registerProperties(getClass()); |
| packetService.addProcessor(packetProcessor, PacketProcessor.director(0)); |
| leadershipService.runForLeadership(appId.name()); |
| |
| log.info("Started"); |
| } |
| |
| @Deactivate |
| protected void deactivate() { |
| packetService.removeProcessor(packetProcessor); |
| osNodeService.removeListener(osNodeListener); |
| configService.unregisterProperties(getClass(), false); |
| leadershipService.withdraw(appId.name()); |
| |
| log.info("Stopped"); |
| } |
| |
| @Modified |
| protected void modified(ComponentContext context) { |
| Dictionary<?, ?> properties = context.getProperties(); |
| String updatedMac; |
| |
| updatedMac = Tools.get(properties, DHCP_SERVER_MAC); |
| |
| if (!Strings.isNullOrEmpty(updatedMac) && !updatedMac.equals(dhcpServerMac)) { |
| dhcpServerMac = updatedMac; |
| } |
| |
| log.info("Modified"); |
| } |
| |
| private class InternalPacketProcessor implements PacketProcessor { |
| |
| @Override |
| public void process(PacketContext context) { |
| if (context.isHandled()) { |
| return; |
| } |
| |
| Ethernet ethPacket = context.inPacket().parsed(); |
| if (ethPacket == null || ethPacket.getEtherType() != Ethernet.TYPE_IPV4) { |
| return; |
| } |
| IPv4 ipv4Packet = (IPv4) ethPacket.getPayload(); |
| if (ipv4Packet.getProtocol() != IPv4.PROTOCOL_UDP) { |
| return; |
| } |
| UDP udpPacket = (UDP) ipv4Packet.getPayload(); |
| if (udpPacket.getDestinationPort() != UDP.DHCP_SERVER_PORT || |
| udpPacket.getSourcePort() != UDP.DHCP_CLIENT_PORT) { |
| return; |
| } |
| |
| DHCP dhcpPacket = (DHCP) udpPacket.getPayload(); |
| processDhcp(context, dhcpPacket); |
| } |
| |
| private void processDhcp(PacketContext context, DHCP dhcpPacket) { |
| if (dhcpPacket == null) { |
| log.trace("DHCP packet without payload received, do nothing"); |
| return; |
| } |
| |
| DHCP.MsgType inPacketType = getPacketType(dhcpPacket); |
| if (inPacketType == null || dhcpPacket.getClientHardwareAddress() == null) { |
| log.trace("Malformed DHCP packet received, ignore it"); |
| return; |
| } |
| |
| MacAddress clientMac = MacAddress.valueOf(dhcpPacket.getClientHardwareAddress()); |
| InstancePort reqInstPort = instancePortService.instancePort(clientMac); |
| if (reqInstPort == null) { |
| log.trace("Failed to find host(MAC:{})", clientMac); |
| return; |
| } |
| Ethernet ethPacket = context.inPacket().parsed(); |
| switch (inPacketType) { |
| case DHCPDISCOVER: |
| log.trace("DHCP DISCOVER received from {}", clientMac); |
| Ethernet discoverReply = buildReply( |
| ethPacket, |
| (byte) DHCPOFFER.getValue(), |
| reqInstPort); |
| sendReply(context, discoverReply); |
| log.trace("DHCP OFFER({}) is sent for {}", |
| reqInstPort.ipAddress(), clientMac); |
| break; |
| case DHCPREQUEST: |
| log.trace("DHCP REQUEST received from {}", clientMac); |
| Ethernet requestReply = buildReply( |
| ethPacket, |
| (byte) DHCPACK.getValue(), |
| reqInstPort); |
| sendReply(context, requestReply); |
| log.trace("DHCP ACK({}) is sent for {}", |
| reqInstPort.ipAddress(), clientMac); |
| break; |
| case DHCPRELEASE: |
| log.trace("DHCP RELEASE received from {}", clientMac); |
| // do nothing |
| break; |
| default: |
| break; |
| } |
| } |
| |
| private DHCP.MsgType getPacketType(DHCP dhcpPacket) { |
| DhcpOption optType = dhcpPacket.getOption(OptionCode_MessageType); |
| if (optType == null) { |
| log.trace("DHCP packet with no message type, ignore it"); |
| return null; |
| } |
| |
| DHCP.MsgType inPacketType = DHCP.MsgType.getType(optType.getData()[0]); |
| if (inPacketType == null) { |
| log.trace("DHCP packet with no packet type, ignore it"); |
| } |
| return inPacketType; |
| } |
| |
| private Ethernet buildReply(Ethernet ethRequest, byte packetType, |
| InstancePort reqInstPort) { |
| log.trace("Build for DHCP reply msg for instance port {}", reqInstPort.toString()); |
| Port osPort = osNetworkService.port(reqInstPort.portId()); |
| if (osPort == null) { |
| log.error("Failed to retrieve openstack port information for instance port {}", |
| reqInstPort.toString()); |
| return null; |
| } |
| // pick one IP address to make a reply |
| IP fixedIp = osPort.getFixedIps().stream().findFirst().get(); |
| Subnet osSubnet = osNetworkService.subnet(fixedIp.getSubnetId()); |
| |
| Ethernet ethReply = new Ethernet(); |
| ethReply.setSourceMACAddress(dhcpServerMac); |
| ethReply.setDestinationMACAddress(ethRequest.getSourceMAC()); |
| ethReply.setEtherType(Ethernet.TYPE_IPV4); |
| |
| IPv4 ipv4Request = (IPv4) ethRequest.getPayload(); |
| IPv4 ipv4Reply = new IPv4(); |
| |
| ipv4Reply.setSourceAddress(clusterService.getLocalNode().ip().getIp4Address().toString()); |
| ipv4Reply.setDestinationAddress(reqInstPort.ipAddress().getIp4Address().toInt()); |
| ipv4Reply.setTtl(PACKET_TTL); |
| |
| UDP udpRequest = (UDP) ipv4Request.getPayload(); |
| UDP udpReply = new UDP(); |
| udpReply.setSourcePort((byte) UDP.DHCP_SERVER_PORT); |
| udpReply.setDestinationPort((byte) UDP.DHCP_CLIENT_PORT); |
| |
| DHCP dhcpRequest = (DHCP) udpRequest.getPayload(); |
| DHCP dhcpReply = buildDhcpReply( |
| dhcpRequest, |
| packetType, |
| reqInstPort.ipAddress().getIp4Address(), |
| osSubnet); |
| |
| udpReply.setPayload(dhcpReply); |
| ipv4Reply.setPayload(udpReply); |
| ethReply.setPayload(ipv4Reply); |
| |
| return ethReply; |
| } |
| |
| private void sendReply(PacketContext context, Ethernet ethReply) { |
| if (ethReply == null) { |
| return; |
| } |
| ConnectPoint srcPoint = context.inPacket().receivedFrom(); |
| TrafficTreatment treatment = DefaultTrafficTreatment |
| .builder() |
| .setOutput(srcPoint.port()) |
| .build(); |
| |
| packetService.emit(new DefaultOutboundPacket( |
| srcPoint.deviceId(), |
| treatment, |
| ByteBuffer.wrap(ethReply.serialize()))); |
| context.block(); |
| } |
| |
| private DHCP buildDhcpReply(DHCP request, byte msgType, Ip4Address yourIp, |
| Subnet osSubnet) { |
| Ip4Address gatewayIp = clusterService.getLocalNode().ip().getIp4Address(); |
| int subnetPrefixLen = IpPrefix.valueOf(osSubnet.getCidr()).prefixLength(); |
| |
| DHCP dhcpReply = new DHCP(); |
| dhcpReply.setOpCode(DHCP.OPCODE_REPLY); |
| dhcpReply.setHardwareType(DHCP.HWTYPE_ETHERNET); |
| dhcpReply.setHardwareAddressLength((byte) 6); |
| dhcpReply.setTransactionId(request.getTransactionId()); |
| dhcpReply.setFlags(request.getFlags()); |
| dhcpReply.setYourIPAddress(yourIp.toInt()); |
| dhcpReply.setServerIPAddress(gatewayIp.toInt()); |
| dhcpReply.setClientHardwareAddress(request.getClientHardwareAddress()); |
| |
| List<DhcpOption> options = Lists.newArrayList(); |
| // message type |
| DhcpOption option = new DhcpOption(); |
| option.setCode(OptionCode_MessageType.getValue()); |
| option.setLength((byte) 1); |
| byte[] optionData = {msgType}; |
| option.setData(optionData); |
| options.add(option); |
| |
| // server identifier |
| option = new DhcpOption(); |
| option.setCode(OptionCode_DHCPServerIp.getValue()); |
| option.setLength((byte) 4); |
| option.setData(gatewayIp.toOctets()); |
| options.add(option); |
| |
| // lease time |
| option = new DhcpOption(); |
| option.setCode(OptionCode_LeaseTime.getValue()); |
| option.setLength((byte) 4); |
| option.setData(DHCP_DATA_LEASE_INFINITE); |
| options.add(option); |
| |
| // subnet mask |
| Ip4Address subnetMask = Ip4Address.makeMaskPrefix(subnetPrefixLen); |
| option = new DhcpOption(); |
| option.setCode(OptionCode_SubnetMask.getValue()); |
| option.setLength((byte) 4); |
| option.setData(subnetMask.toOctets()); |
| options.add(option); |
| |
| // broadcast address |
| Ip4Address broadcast = Ip4Address.makeMaskedAddress(yourIp, subnetPrefixLen); |
| option = new DhcpOption(); |
| option.setCode(OptionCode_BroadcastAddress.getValue()); |
| option.setLength((byte) 4); |
| option.setData(broadcast.toOctets()); |
| options.add(option); |
| |
| // domain server |
| option = new DhcpOption(); |
| |
| List<String> dnsServers = osSubnet.getDnsNames(); |
| option.setCode(OptionCode_DomainServer.getValue()); |
| |
| if (dnsServers.isEmpty()) { |
| option.setLength((byte) 8); |
| ByteBuffer dnsByteBuf = ByteBuffer.allocate(8); |
| dnsByteBuf.put(DEFAULT_PRIMARY_DNS.toOctets()); |
| dnsByteBuf.put(DEFAULT_SECONDARY_DNS.toOctets()); |
| |
| option.setData(dnsByteBuf.array()); |
| } else { |
| int dnsLength = 4 * dnsServers.size(); |
| |
| option.setLength((byte) dnsLength); |
| |
| ByteBuffer dnsByteBuf = ByteBuffer.allocate(8); |
| |
| for (int i = 0; i < dnsServers.size(); i++) { |
| dnsByteBuf.put(IpAddress.valueOf(dnsServers.get(i)).toOctets()); |
| } |
| option.setData(dnsByteBuf.array()); |
| } |
| |
| options.add(option); |
| |
| option = new DhcpOption(); |
| option.setCode(DHCP_OPTION_MTU); |
| option.setLength((byte) 2); |
| Network osNetwork = osNetworkService.network(osSubnet.getNetworkId()); |
| checkNotNull(osNetwork); |
| checkNotNull(osNetwork.getMTU()); |
| |
| option.setData(ByteBuffer.allocate(2).putShort(osNetwork.getMTU().shortValue()).array()); |
| options.add(option); |
| |
| // classless static route |
| if (!osSubnet.getHostRoutes().isEmpty()) { |
| option = new DhcpOption(); |
| option.setCode(OptionCode_Classless_Static_Route.getValue()); |
| |
| int hostRoutesSize = hostRoutesSize(ImmutableList.copyOf(osSubnet.getHostRoutes())); |
| if (hostRoutesSize == 0) { |
| throw new IllegalArgumentException("Illegal CIDR hostRoutesSize value!"); |
| } |
| |
| log.trace("hostRouteSize: {}", hostRoutesSize); |
| |
| option.setLength((byte) hostRoutesSize); |
| ByteBuffer hostRouteByteBuf = ByteBuffer.allocate(hostRoutesSize); |
| |
| osSubnet.getHostRoutes().forEach(h -> { |
| log.debug("processing host route information: {}", h.toString()); |
| |
| IpPrefix ipPrefix = IpPrefix.valueOf(h.getDestination()); |
| |
| hostRouteByteBuf.put(bytesDestinationDescriptor(ipPrefix)); |
| |
| hostRouteByteBuf.put(Ip4Address.valueOf(h.getNexthop()).toOctets()); |
| }); |
| |
| option.setData(hostRouteByteBuf.array()); |
| |
| options.add(option); |
| } |
| |
| // Sets the default router address up. |
| // Performs only if the gateway is set in subnet. |
| if (!Strings.isNullOrEmpty(osSubnet.getGateway())) { |
| option = new DhcpOption(); |
| option.setCode(OptionCode_RouterAddress.getValue()); |
| option.setLength((byte) 4); |
| option.setData(Ip4Address.valueOf(osSubnet.getGateway()).toOctets()); |
| options.add(option); |
| } |
| |
| // end option |
| option = new DhcpOption(); |
| option.setCode(OptionCode_END.getValue()); |
| option.setLength((byte) 1); |
| options.add(option); |
| |
| dhcpReply.setOptions(options); |
| return dhcpReply; |
| } |
| |
| private int hostRoutesSize(List<HostRoute> hostRoutes) { |
| int size = 0; |
| int preFixLen; |
| |
| for (HostRoute h : hostRoutes) { |
| preFixLen = IpPrefix.valueOf(h.getDestination()).prefixLength(); |
| if (Math.max(V4_CIDR_LOWER_BOUND, preFixLen) == V4_CIDR_LOWER_BOUND || |
| Math.min(preFixLen, V4_CIDR_UPPER_BOUND) == V4_CIDR_UPPER_BOUND) { |
| throw new IllegalArgumentException("Illegal CIDR length value!"); |
| } |
| |
| for (int i = 0; i <= V4_BYTE_SIZE; i++) { |
| if (preFixLen == Math.min(preFixLen, i * OCTET_BIT_LENGTH)) { |
| size = size + i + 1 + PADDING_SIZE; |
| break; |
| } |
| } |
| } |
| return size; |
| } |
| |
| private byte[] bytesDestinationDescriptor(IpPrefix ipPrefix) { |
| ByteBuffer byteBuffer; |
| int prefixLen = ipPrefix.prefixLength(); |
| |
| // retrieve ipPrefix to the destination descriptor format |
| // ex) 10.1.1.0/24 -> [10,1,1,0] |
| String[] ipPrefixString = ipPrefix.getIp4Prefix().toString() |
| .split("/")[0] |
| .split("\\."); |
| |
| // retrieve destination descriptor and put this to bytebuffer according to RFC 3442 |
| // ex) 0.0.0.0/0 -> 0 |
| // ex) 10.0.0.0/8 -> 8.10 |
| // ex) 10.17.0.0/16 -> 16.10.17 |
| // ex) 10.27.129.0/24 -> 24.10.27.129 |
| // ex) 10.229.0.128/25 -> 25.10.229.0.128 |
| for (int i = 0; i <= V4_BYTE_SIZE; i++) { |
| if (prefixLen == Math.min(prefixLen, i * OCTET_BIT_LENGTH)) { |
| byteBuffer = ByteBuffer.allocate(i + 1); |
| byteBuffer.put((byte) prefixLen); |
| |
| for (int j = 0; j < i; j++) { |
| byteBuffer.put((byte) Integer.parseInt(ipPrefixString[j])); |
| } |
| return byteBuffer.array(); |
| } |
| } |
| |
| return null; |
| } |
| } |
| |
| private class InternalNodeEventListener implements OpenstackNodeListener { |
| @Override |
| public boolean isRelevant(OpenstackNodeEvent event) { |
| // do not allow to proceed without leadership |
| NodeId leader = leadershipService.getLeader(appId.name()); |
| return Objects.equals(localNodeId, leader) && event.subject().type() == COMPUTE; |
| } |
| |
| @Override |
| public void event(OpenstackNodeEvent event) { |
| OpenstackNode osNode = event.subject(); |
| switch (event.type()) { |
| case OPENSTACK_NODE_COMPLETE: |
| setDhcpRule(osNode, true); |
| break; |
| case OPENSTACK_NODE_INCOMPLETE: |
| setDhcpRule(osNode, false); |
| break; |
| case OPENSTACK_NODE_CREATED: |
| case OPENSTACK_NODE_UPDATED: |
| case OPENSTACK_NODE_REMOVED: |
| default: |
| break; |
| } |
| } |
| |
| private void setDhcpRule(OpenstackNode openstackNode, boolean install) { |
| TrafficSelector selector = DefaultTrafficSelector.builder() |
| .matchEthType(Ethernet.TYPE_IPV4) |
| .matchIPProtocol(IPv4.PROTOCOL_UDP) |
| .matchUdpDst(TpPort.tpPort(UDP.DHCP_SERVER_PORT)) |
| .matchUdpSrc(TpPort.tpPort(UDP.DHCP_CLIENT_PORT)) |
| .build(); |
| |
| TrafficTreatment treatment = DefaultTrafficTreatment.builder() |
| .punt() |
| .build(); |
| |
| osFlowRuleService.setRule( |
| appId, |
| openstackNode.intgBridge(), |
| selector, |
| treatment, |
| PRIORITY_DHCP_RULE, |
| DHCP_ARP_TABLE, |
| install); |
| } |
| } |
| } |