NETVIRT-1630 migrate to md-sal APIs
[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.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;
28
29 @Singleton
30 public class NatArpNotificationHandler implements OdlArputilListener {
31
32     private static final Logger LOG = LoggerFactory.getLogger(NatArpNotificationHandler.class);
33
34     private final DataBroker dataBroker;
35     private final IElanService elanService;
36     private final NatSouthboundEventHandlers southboundEventHandlers;
37     private final VipStateTracker vipStateTracker;
38
39     @Inject
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;
48     }
49
50     @Override
51     public void onArpResponseReceived(ArpResponseReceived notification) {
52
53     }
54
55     @Override
56     public void onMacChanged(MacChanged notification) {
57
58     }
59
60     @Override
61     public void onArpRequestReceived(ArpRequestReceived notification) {
62
63         LOG.debug("NatArpNotificationHandler received {}", notification);
64
65         IpAddress srcIp = notification.getSrcIpaddress();
66         if (srcIp == null || !Objects.equals(srcIp, notification.getDstIpaddress())) {
67             LOG.debug("NatArpNotificationHandler: ignoring ARP packet, not gratuitous {}", notification);
68             return;
69         }
70
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. {}",
76                     notification);
77             return;
78         }
79
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;
85                 break;
86             }
87         }
88
89         if (null == targetIfc) {
90             LOG.warn("NatArpNotificationHandler: GARP does not correspond to an interface in this elan {}",
91                      notification);
92             return;
93         }
94
95         RouterInterface routerInterface = NatUtil.getConfiguredRouterInterface(dataBroker, targetIfc.getName());
96         if (null == routerInterface) {
97             LOG.warn("NatArpNotificationHandler: Could not retrieve router ifc for {}", targetIfc);
98             return;
99         }
100
101         VipState newVipState = this.vipStateTracker.buildVipState(srcIp.getIpv4Address().getValue(),
102             notification.getDpnId(), targetIfc.getName());
103         VipState cachedState = null;
104         try {
105             cachedState = this.vipStateTracker.get(newVipState.getIp()).orElse(null);
106         } catch (ReadFailedException e) {
107             LOG.warn("NatArpNotificationHandler failed to read vip state {}", notification, e);
108         }
109
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);
119         }
120
121     }
122
123     private boolean ipBelongsToElanInterface(ElanInterface elanInterface, IpAddress ip) {
124         if (elanInterface == null) {
125             return false;
126         }
127
128         List<StaticMacEntries> staticMacEntries = elanInterface.getStaticMacEntries();
129         if (null == staticMacEntries) {
130             return false;
131         }
132
133         for (StaticMacEntries staticMacEntry :  staticMacEntries) {
134             if (Objects.equals(staticMacEntry.getIpPrefix(), ip)) {
135                 return true;
136             }
137         }
138         return false;
139     }
140 }