Freeze upstream versions
[netvirt.git] / natservice / impl / src / main / java / org / opendaylight / netvirt / natservice / internal / NatArpNotificationHandler.java
1 /*
2  * Copyright (c) 2018 Red Hat, Inc. and others. All rights reserved.
3  *
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
7  */
8 package org.opendaylight.netvirt.natservice.internal;
9
10 import java.util.Map;
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;
29
30 @Singleton
31 public class NatArpNotificationHandler implements OdlArputilListener {
32
33     private static final Logger LOG = LoggerFactory.getLogger(NatArpNotificationHandler.class);
34
35     private final DataBroker dataBroker;
36     private final IElanService elanService;
37     private final NatSouthboundEventHandlers southboundEventHandlers;
38     private final VipStateTracker vipStateTracker;
39
40     @Inject
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;
49     }
50
51     @Override
52     public void onArpResponseReceived(ArpResponseReceived notification) {
53
54     }
55
56     @Override
57     public void onMacChanged(MacChanged notification) {
58
59     }
60
61     @Override
62     public void onArpRequestReceived(ArpRequestReceived notification) {
63
64         LOG.debug("NatArpNotificationHandler received {}", notification);
65
66         IpAddress srcIp = notification.getSrcIpaddress();
67         if (srcIp == null || !Objects.equals(srcIp, notification.getDstIpaddress())) {
68             LOG.debug("NatArpNotificationHandler: ignoring ARP packet, not gratuitous {}", notification);
69             return;
70         }
71
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. {}",
77                     notification);
78             return;
79         }
80
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;
86                 break;
87             }
88         }
89
90         if (null == targetIfc) {
91             LOG.warn("NatArpNotificationHandler: GARP does not correspond to an interface in this elan {}",
92                      notification);
93             return;
94         }
95
96         RouterInterface routerInterface = NatUtil.getConfiguredRouterInterface(dataBroker, targetIfc.getName());
97         if (null == routerInterface) {
98             LOG.warn("NatArpNotificationHandler: Could not retrieve router ifc for {}", targetIfc);
99             return;
100         }
101
102         VipState newVipState = this.vipStateTracker.buildVipState(srcIp.getIpv4Address().getValue(),
103             notification.getDpnId(), targetIfc.getName());
104         VipState cachedState = null;
105         try {
106             cachedState = this.vipStateTracker.get(newVipState.getIp()).orElse(null);
107         } catch (ReadFailedException e) {
108             LOG.warn("NatArpNotificationHandler failed to read vip state {}", notification, e);
109         }
110
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);
120         }
121
122     }
123
124     private boolean ipBelongsToElanInterface(ElanInterface elanInterface, IpAddress ip) {
125         if (elanInterface == null) {
126             return false;
127         }
128
129         Map<StaticMacEntriesKey, StaticMacEntries> keyStaticMacEntriesMap = elanInterface.getStaticMacEntries();
130         if (null == keyStaticMacEntriesMap) {
131             return false;
132         }
133
134         for (StaticMacEntries staticMacEntry :  keyStaticMacEntriesMap.values()) {
135             if (Objects.equals(staticMacEntry.getIpPrefix(), ip)) {
136                 return true;
137             }
138         }
139         return false;
140     }
141 }