Bump upstreams
[lispflowmapping.git] / mappingservice / southbound / src / main / java / org / opendaylight / lispflowmapping / southbound / lisp / AuthenticationKeyDataListener.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc.  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.lispflowmapping.southbound.lisp;
9
10 import java.util.List;
11 import java.util.Map;
12 import java.util.concurrent.ConcurrentHashMap;
13 import org.opendaylight.lispflowmapping.lisp.util.LispAddressUtil;
14 import org.opendaylight.lispflowmapping.mapcache.AuthKeyDb;
15 import org.opendaylight.mdsal.binding.api.DataBroker;
16 import org.opendaylight.mdsal.binding.api.DataObjectModification;
17 import org.opendaylight.mdsal.binding.api.DataObjectModification.ModificationType;
18 import org.opendaylight.mdsal.binding.api.DataTreeChangeListener;
19 import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
20 import org.opendaylight.mdsal.binding.api.DataTreeModification;
21 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.eid.container.Eid;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.map.register.cache.metadata.container.map.register.cache.metadata.EidLispAddress;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.map.register.cache.metadata.container.map.register.cache.metadata.EidLispAddressKey;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.MappingDatabase;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.db.instance.AuthenticationKey;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.db.instance.AuthenticationKeyBuilder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.mappingservice.rev150906.mapping.database.VirtualNetworkIdentifier;
29 import org.opendaylight.yangtools.concepts.Registration;
30 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34 /**
35  * DataListener for all AuthenticationKey modification events.
36  *
37  */
38 public class AuthenticationKeyDataListener implements DataTreeChangeListener<AuthenticationKey> {
39     private static final Logger LOG = LoggerFactory.getLogger(AuthenticationKeyDataListener.class);
40
41     private final AuthKeyDb akdb;
42     private final InstanceIdentifier<AuthenticationKey> path;
43     private final Registration registration;
44     private final ConcurrentHashMap<Eid, Long> updatedEntries;
45
46     public AuthenticationKeyDataListener(final DataBroker broker, final AuthKeyDb akdb) {
47         this.akdb = akdb;
48         path = InstanceIdentifier.create(MappingDatabase.class).child(VirtualNetworkIdentifier.class)
49                 .child(AuthenticationKey.class);
50         LOG.trace("Registering AuthenticationKey listener.");
51         registration = broker.registerTreeChangeListener(
52             DataTreeIdentifier.of(LogicalDatastoreType.CONFIGURATION, path), this);
53         updatedEntries = new ConcurrentHashMap<>();
54     }
55
56     public void closeDataChangeListener() {
57         registration.close();
58     }
59
60     @Override
61     public synchronized void onDataTreeChanged(final List<DataTreeModification<AuthenticationKey>> changes) {
62         for (DataTreeModification<AuthenticationKey> change : changes) {
63             final DataObjectModification<AuthenticationKey> mod = change.getRootNode();
64
65             if (ModificationType.DELETE == mod.modificationType()) {
66                 final AuthenticationKey authKey = mod.dataBefore();
67
68                 LOG.trace("Received deleted data");
69                 LOG.trace("Key: {}", change.getRootPath().path());
70                 LOG.trace("Value: {}", authKey);
71
72                 final AuthenticationKey convertedAuthKey = convertToBinaryIfNecessary(authKey);
73
74                 akdb.removeAuthenticationKey(convertedAuthKey.getEid());
75                 updatedEntries.put(convertedAuthKey.getEid(), System.currentTimeMillis());
76             } else if (ModificationType.WRITE == mod.modificationType()
77                     || ModificationType.SUBTREE_MODIFIED == mod.modificationType()) {
78                 if (ModificationType.WRITE == mod.modificationType()) {
79                     LOG.trace("Received created data");
80                 } else {
81                     LOG.trace("Received updated data");
82                 }
83                 // Process newly created or updated authentication keys
84                 final AuthenticationKey authKey = mod.dataAfter();
85
86                 LOG.trace("Key: {}", change.getRootPath().path());
87                 LOG.trace("Value: {}", authKey);
88
89                 final AuthenticationKey convertedAuthKey = convertToBinaryIfNecessary(authKey);
90
91                 akdb.addAuthenticationKey(convertedAuthKey.getEid(), convertedAuthKey.getMappingAuthkey());
92                 updatedEntries.put(convertedAuthKey.getEid(), System.currentTimeMillis());
93             } else {
94                 LOG.warn("Ignoring unhandled modification type {}", mod.modificationType());
95             }
96         }
97     }
98
99     /**
100      * We maintain a HashMap with the update times of AuthenticationKey objects in the updatedEntries field. We keep
101      * entries in the HashMap for the Map-Register cache timeout interval, and lazy remove them afterwards. As a result
102      * the same EID will be considered updated during that interval, even on subsequent queries. This is necessary
103      * because more than one xTR may register the same EID, and to avoid complexity we don't store origin information.
104      * The performance trade-off is not significant, because during a typical cache timeout the same xTR will send only
105      * a few registration packets (2 for the default value of 90s, when UDP Map-Registers are sent at 1 minute
106      * intervals).
107      *
108      * @param eids List of EIDs to check
109      * @param timeout MapRegister cache timeout value
110      * @return false if any of the EIDs in the eids list was updated in the last timout period, true otherwise
111      */
112     public synchronized boolean authKeysForEidsUnchanged(final Map<EidLispAddressKey, EidLispAddress> eids,
113             final long timeout) {
114         boolean result = true;
115         Long currentTime = System.currentTimeMillis();
116         for (EidLispAddress eidLispAddress : eids.values()) {
117             Long updateTime = updatedEntries.get(eidLispAddress.getEid());
118             if (updateTime != null) {
119                 result = false;
120                 if (currentTime - updateTime > timeout) {
121                     updatedEntries.remove(eidLispAddress.getEid());
122                 }
123             }
124         }
125         return result;
126     }
127
128     private static AuthenticationKey convertToBinaryIfNecessary(final AuthenticationKey authKey) {
129         Eid originalEid = authKey.getEid();
130         if (LispAddressUtil.addressNeedsConversionToBinary(originalEid.getAddress())) {
131             AuthenticationKeyBuilder akb = new AuthenticationKeyBuilder(authKey);
132             akb.setEid(LispAddressUtil.convertToBinary(originalEid));
133             return akb.build();
134         }
135         return authKey;
136     }
137
138 }