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;
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.elan.rev150602.elan.interfaces.elan._interface.StaticMacEntriesKey;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.router.interfaces.RouterInterface;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.neutron.vip.states.VipState;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
31 public class NatArpNotificationHandler implements OdlArputilListener {
33 private static final Logger LOG = LoggerFactory.getLogger(NatArpNotificationHandler.class);
35 private final DataBroker dataBroker;
36 private final IElanService elanService;
37 private final NatSouthboundEventHandlers southboundEventHandlers;
38 private final VipStateTracker vipStateTracker;
41 public NatArpNotificationHandler(final DataBroker dataBroker,
42 final IElanService elanService,
43 final NatSouthboundEventHandlers southboundEventHandlers,
44 final VipStateTracker vipStateTracker) {
45 this.dataBroker = dataBroker;
46 this.elanService = elanService;
47 this.southboundEventHandlers = southboundEventHandlers;
48 this.vipStateTracker = vipStateTracker;
52 public void onArpResponseReceived(ArpResponseReceived notification) {
57 public void onMacChanged(MacChanged notification) {
62 public void onArpRequestReceived(ArpRequestReceived notification) {
64 LOG.debug("NatArpNotificationHandler received {}", notification);
66 IpAddress srcIp = notification.getSrcIpaddress();
67 if (srcIp == null || !Objects.equals(srcIp, notification.getDstIpaddress())) {
68 LOG.debug("NatArpNotificationHandler: ignoring ARP packet, not gratuitous {}", notification);
72 //Since the point of all this is to learn VIPs those are by definition
73 //not the IP addresses assigned to a port by neutron configuration.
74 ElanInterface arpSenderIfc = elanService.getElanInterfaceByElanInterfaceName(notification.getInterface());
75 if (ipBelongsToElanInterface(arpSenderIfc, srcIp)) {
76 LOG.debug("NatArpNotificationHandler: ignoring GARP packet. No need to NAT a port's static IP. {}",
81 ElanInterface targetIfc = null;
82 for (String ifcName : elanService.getElanInterfaces(arpSenderIfc.getElanInstanceName())) {
83 ElanInterface elanInterface = elanService.getElanInterfaceByElanInterfaceName(ifcName);
84 if (ipBelongsToElanInterface(elanInterface, srcIp)) {
85 targetIfc = elanInterface;
90 if (null == targetIfc) {
91 LOG.warn("NatArpNotificationHandler: GARP does not correspond to an interface in this elan {}",
96 RouterInterface routerInterface = NatUtil.getConfiguredRouterInterface(dataBroker, targetIfc.getName());
97 if (null == routerInterface) {
98 LOG.warn("NatArpNotificationHandler: Could not retrieve router ifc for {}", targetIfc);
102 VipState newVipState = this.vipStateTracker.buildVipState(srcIp.getIpv4Address().getValue(),
103 notification.getDpnId(), targetIfc.getName());
104 VipState cachedState = null;
106 cachedState = this.vipStateTracker.get(newVipState.getIp()).orElse(null);
107 } catch (ReadFailedException e) {
108 LOG.warn("NatArpNotificationHandler failed to read vip state {}", notification, e);
111 if (null == cachedState) {
112 this.southboundEventHandlers.handleAdd(
113 targetIfc.getName(), notification.getDpnId(),
114 routerInterface, newVipState);
115 } else if (!cachedState.getDpnId().equals(newVipState.getDpnId())) {
116 this.southboundEventHandlers.handleRemove(cachedState.getIfcName(),
117 cachedState.getDpnId(), routerInterface);
118 this.southboundEventHandlers.handleAdd(
119 targetIfc.getName(), notification.getDpnId(), routerInterface, newVipState);
124 private boolean ipBelongsToElanInterface(ElanInterface elanInterface, IpAddress ip) {
125 if (elanInterface == null) {
129 Map<StaticMacEntriesKey, StaticMacEntries> keyStaticMacEntriesMap = elanInterface.getStaticMacEntries();
130 if (null == keyStaticMacEntriesMap) {
134 for (StaticMacEntries staticMacEntry : keyStaticMacEntriesMap.values()) {
135 if (Objects.equals(staticMacEntry.getIpPrefix(), ip)) {