2 * Copyright (c) 2018 Red Hat, Inc. 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.natservice.internal;
10 import java.util.List;
11 import java.util.Objects;
12 import javax.inject.Inject;
13 import javax.inject.Singleton;
14 import org.opendaylight.mdsal.binding.api.DataBroker;
15 import org.opendaylight.mdsal.common.api.ReadFailedException;
16 import org.opendaylight.netvirt.elanmanager.api.IElanService;
17 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.ArpRequestReceived;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.ArpResponseReceived;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.MacChanged;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.OdlArputilListener;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.elan._interface.StaticMacEntries;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.router.interfaces.RouterInterface;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.neutron.vip.states.VipState;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
30 public class NatArpNotificationHandler implements OdlArputilListener {
32 private static final Logger LOG = LoggerFactory.getLogger(NatArpNotificationHandler.class);
34 private final DataBroker dataBroker;
35 private final IElanService elanService;
36 private final NatSouthboundEventHandlers southboundEventHandlers;
37 private final VipStateTracker vipStateTracker;
40 public NatArpNotificationHandler(final DataBroker dataBroker,
41 final IElanService elanService,
42 final NatSouthboundEventHandlers southboundEventHandlers,
43 final VipStateTracker vipStateTracker) {
44 this.dataBroker = dataBroker;
45 this.elanService = elanService;
46 this.southboundEventHandlers = southboundEventHandlers;
47 this.vipStateTracker = vipStateTracker;
51 public void onArpResponseReceived(ArpResponseReceived notification) {
56 public void onMacChanged(MacChanged notification) {
61 public void onArpRequestReceived(ArpRequestReceived notification) {
63 LOG.debug("NatArpNotificationHandler received {}", notification);
65 IpAddress srcIp = notification.getSrcIpaddress();
66 if (srcIp == null || !Objects.equals(srcIp, notification.getDstIpaddress())) {
67 LOG.debug("NatArpNotificationHandler: ignoring ARP packet, not gratuitous {}", notification);
71 //Since the point of all this is to learn VIPs those are by definition
72 //not the IP addresses assigned to a port by neutron configuration.
73 ElanInterface arpSenderIfc = elanService.getElanInterfaceByElanInterfaceName(notification.getInterface());
74 if (ipBelongsToElanInterface(arpSenderIfc, srcIp)) {
75 LOG.debug("NatArpNotificationHandler: ignoring GARP packet. No need to NAT a port's static IP. {}",
80 ElanInterface targetIfc = null;
81 for (String ifcName : elanService.getElanInterfaces(arpSenderIfc.getElanInstanceName())) {
82 ElanInterface elanInterface = elanService.getElanInterfaceByElanInterfaceName(ifcName);
83 if (ipBelongsToElanInterface(elanInterface, srcIp)) {
84 targetIfc = elanInterface;
89 if (null == targetIfc) {
90 LOG.warn("NatArpNotificationHandler: GARP does not correspond to an interface in this elan {}",
95 RouterInterface routerInterface = NatUtil.getConfiguredRouterInterface(dataBroker, targetIfc.getName());
96 if (null == routerInterface) {
97 LOG.warn("NatArpNotificationHandler: Could not retrieve router ifc for {}", targetIfc);
101 VipState newVipState = this.vipStateTracker.buildVipState(srcIp.getIpv4Address().getValue(),
102 notification.getDpnId(), targetIfc.getName());
103 VipState cachedState = null;
105 cachedState = this.vipStateTracker.get(newVipState.getIp()).orElse(null);
106 } catch (ReadFailedException e) {
107 LOG.warn("NatArpNotificationHandler failed to read vip state {}", notification, e);
110 if (null == cachedState) {
111 this.southboundEventHandlers.handleAdd(
112 targetIfc.getName(), notification.getDpnId(),
113 routerInterface, newVipState);
114 } else if (!cachedState.getDpnId().equals(newVipState.getDpnId())) {
115 this.southboundEventHandlers.handleRemove(cachedState.getIfcName(),
116 cachedState.getDpnId(), routerInterface);
117 this.southboundEventHandlers.handleAdd(
118 targetIfc.getName(), notification.getDpnId(), routerInterface, newVipState);
123 private boolean ipBelongsToElanInterface(ElanInterface elanInterface, IpAddress ip) {
124 if (elanInterface == null) {
128 List<StaticMacEntries> staticMacEntries = elanInterface.getStaticMacEntries();
129 if (null == staticMacEntries) {
133 for (StaticMacEntries staticMacEntry : staticMacEntries) {
134 if (Objects.equals(staticMacEntry.getIpPrefix(), ip)) {