2 * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.netvirt.vpnmanager;
10 import com.google.common.base.Optional;
11 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
12 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
13 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
14 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
15 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
16 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.ArpRequestReceived;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.ArpResponseReceived;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.MacChanged;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.OdlArputilListener;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.id.to.vpn.instance.VpnIds;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.neutron.vpn.portip.port.data.VpnPortipToPort;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.PortKey;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.Subnets;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.SubnetKey;
30 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
34 import java.math.BigInteger;
36 public class ArpNotificationHandler implements OdlArputilListener {
38 VpnInterfaceManager vpnIfManager;
41 private static final Logger LOG = LoggerFactory.getLogger(ArpNotificationHandler.class);
43 public ArpNotificationHandler(VpnInterfaceManager vpnIfMgr, DataBroker dataBroker) {
44 vpnIfManager = vpnIfMgr;
48 public void onMacChanged(MacChanged notification){
52 public void onArpRequestReceived(ArpRequestReceived notification){
53 LOG.trace("ArpNotification Request Received from interface {} and IP {} having MAC {} target destination {}",
54 notification.getInterface(), notification.getSrcIpaddress().getIpv4Address().getValue(),
55 notification.getSrcMac().getValue(),notification.getDstIpaddress().getIpv4Address().getValue());
56 String srcInterface = notification.getInterface();
57 IpAddress srcIP = notification.getSrcIpaddress();
58 PhysAddress srcMac = notification.getSrcMac();
59 IpAddress targetIP = notification.getDstIpaddress();
60 BigInteger metadata = notification.getMetadata();
61 if (metadata != null && metadata != BigInteger.ZERO) {
62 long vpnId = MetaDataUtil.getVpnIdFromMetadata(metadata);
63 // Respond to ARP request only if vpnservice is configured on the interface
64 if (VpnUtil.isVpnInterfaceConfigured(broker, srcInterface)) {
65 LOG.info("Received ARP Request for interface {} ", srcInterface);
66 InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.id.to.vpn.instance.VpnIds>
67 vpnIdsInstanceIdentifier = VpnUtil.getVpnIdToVpnInstanceIdentifier(vpnId);
68 Optional<VpnIds> vpnIdsOptional
69 = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, vpnIdsInstanceIdentifier);
70 if (!vpnIdsOptional.isPresent()) {
71 // Donot respond to ARP requests on unknown VPNs
72 LOG.trace("ARP NO_RESOLVE: VPN {} not configured. Ignoring responding to ARP requests on this VPN", vpnId);
75 String vpnName = vpnIdsOptional.get().getVpnInstanceName();
76 String ipToQuery = notification.getSrcIpaddress().getIpv4Address().getValue();
77 LOG.trace("ArpRequest being processed for Source IP {}", ipToQuery);
78 VpnIds vpnIds = vpnIdsOptional.get();
79 VpnPortipToPort vpnPortipToPort = VpnUtil.getNeutronPortFromVpnPortFixedIp(broker, vpnIds.getVpnInstanceName(), ipToQuery);
80 if (vpnPortipToPort != null) {
81 String oldPortName = vpnPortipToPort.getPortName();
82 String oldMac = vpnPortipToPort.getMacAddress();
83 if (!oldMac.equalsIgnoreCase(srcMac.getValue())) {
84 //MAC has changed for requested IP
85 LOG.trace("ARP request Source IP/MAC data etmodified for IP {} with MAC {} and Port {}", ipToQuery,
86 srcMac, srcInterface);
87 if (!vpnPortipToPort.isConfig()) {
88 VpnUtil.updateVpnPortFixedIpToPort(broker, vpnName, ipToQuery, srcInterface,
89 srcMac.getValue(), false, false, true);
90 vpnIfManager.removeMIPAdjacency(vpnName, oldPortName, srcIP);
93 } catch (Exception e) {
95 vpnIfManager.addMIPAdjacency(vpnName, srcInterface, srcIP);
97 //MAC mismatch for a Neutron learned IP
98 LOG.warn("MAC Address mismatach for Interface {} having a Mac {}, IP {} and Arp learnt Mac {}",
99 oldPortName, oldMac, ipToQuery, srcMac.getValue());
104 VpnUtil.createVpnPortFixedIpToPort(broker, vpnName, ipToQuery, srcInterface, srcMac.getValue(), false, false, true);
105 vpnIfManager.addMIPAdjacency(vpnName, srcInterface, srcIP);
107 String targetIpToQuery = notification.getDstIpaddress().getIpv4Address().getValue();
108 VpnPortipToPort vpnTargetIpToPort = VpnUtil.getNeutronPortFromVpnPortFixedIp(broker,
109 vpnIds.getVpnInstanceName(), targetIpToQuery);
110 //Process and respond from Controller only for GatewayIp ARP request
111 if (vpnTargetIpToPort != null) {
112 if (vpnTargetIpToPort.isSubnetIp()) {
113 String macAddress = vpnTargetIpToPort.getMacAddress();
114 PhysAddress targetMac = new PhysAddress(macAddress);
115 vpnIfManager.processArpRequest(srcIP, srcMac, targetIP, targetMac, srcInterface);
118 //Respond for gateway Ips ARP requests if L3vpn configured without a router
119 if( vpnIds.isExternalVpn()) {
122 Uuid portUuid = new Uuid(srcInterface);
123 InstanceIdentifier<Port> inst = InstanceIdentifier.create(Neutron.class)
125 .child(Port.class, new PortKey(portUuid));
126 Optional<Port> port = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, inst);
127 if (port.isPresent()) {
129 Uuid subnetUUID = prt.getFixedIps().get(0).getSubnetId();
130 LOG.trace("Subnet UUID for this VPN Interface is {}", subnetUUID);
131 SubnetKey subnetkey = new SubnetKey(subnetUUID);
132 InstanceIdentifier<Subnet> subnetidentifier = InstanceIdentifier.create(Neutron.class)
133 .child(Subnets.class)
134 .child(Subnet.class, subnetkey);
135 Optional<Subnet> subnet = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, subnetidentifier);
136 if (subnet.isPresent()) {
137 gw = subnet.get().getGatewayIp().getIpv4Address().getValue();
138 if (targetIpToQuery.equalsIgnoreCase(gw)) {
139 LOG.trace("Target Destination matches the Gateway IP {} so respond for ARP", gw);
140 vpnIfManager.processArpRequest(srcIP, srcMac, targetIP, null, srcInterface);
145 LOG.trace("ARP request is not on an External VPN, so ignoring the request.");
153 public void onArpResponseReceived(ArpResponseReceived notification){
154 LOG.trace("ArpNotification Response Received from interface {} and IP {} having MAC {}",notification.getInterface(),
155 notification.getIpaddress().getIpv4Address().getValue(), notification.getMacaddress().getValue());
156 String srcInterface = notification.getInterface();
157 IpAddress srcIP = notification.getIpaddress();
158 PhysAddress srcMac = notification.getMacaddress();
159 BigInteger metadata = notification.getMetadata();
160 if (metadata != null && metadata != BigInteger.ZERO) {
161 long vpnId = MetaDataUtil.getVpnIdFromMetadata(metadata);
162 InstanceIdentifier<VpnIds>
163 vpnIdsInstanceIdentifier = VpnUtil.getVpnIdToVpnInstanceIdentifier(vpnId);
164 Optional<VpnIds> vpnIdsOptional
165 = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, vpnIdsInstanceIdentifier);
166 if (!vpnIdsOptional.isPresent()) {
167 // Donot respond to ARP requests on unknown VPNs
168 LOG.trace("ARP NO_RESOLVE: VPN {} not configured. Ignoring responding to ARP requests on this VPN", vpnId);
171 if (VpnUtil.isVpnInterfaceConfigured(broker, srcInterface)) {
172 String vpnName = vpnIdsOptional.get().getVpnInstanceName();
173 String ipToQuery = notification.getIpaddress().getIpv4Address().getValue();
174 VpnIds vpnIds = vpnIdsOptional.get();
175 VpnPortipToPort vpnPortipToPort = VpnUtil.getNeutronPortFromVpnPortFixedIp(broker, vpnIds.getVpnInstanceName(), ipToQuery);
176 if (vpnPortipToPort != null) {
177 String oldMac = vpnPortipToPort.getMacAddress();
178 String oldPortName = vpnPortipToPort.getPortName();
179 if (!oldMac.equalsIgnoreCase(srcMac.getValue())) {
180 //MAC has changed for requested IP
181 LOG.trace("ARP response Source IP/MAC data modified for IP {} with MAC {} and Port {}", ipToQuery,
182 srcMac, srcInterface);
183 if (!vpnPortipToPort.isConfig()) {
184 VpnUtil.updateVpnPortFixedIpToPort(broker, vpnName, ipToQuery, srcInterface,
185 srcMac.getValue(), false, false, true);
186 vpnIfManager.removeMIPAdjacency(vpnName, oldPortName, srcIP);
189 } catch (Exception e) {
191 vpnIfManager.addMIPAdjacency(vpnName, srcInterface, srcIP);
193 //MAC mismatch for a Neutron learned IP set learnt back to false
194 LOG.warn("MAC Address mismatch for Interface {} having a Mac {} , IP {} and Arp learnt Mac {}",
195 srcInterface, oldMac, ipToQuery, srcMac.getValue());
199 VpnUtil.createVpnPortFixedIpToPort(broker, vpnName, ipToQuery, srcInterface, srcMac.getValue(), false, false, true);
200 vpnIfManager.addMIPAdjacency(vpnName, srcInterface, srcIP);