BUG-2915: Add support to remove mapping through northbound API 74/17274/3
authorFlorin Coras <fcoras@ac.upc.edu>
Sat, 28 Mar 2015 07:25:53 +0000 (00:25 -0700)
committerFlorin Coras <fcoras@ac.upc.edu>
Mon, 30 Mar 2015 21:21:14 +0000 (14:21 -0700)
This supports removing a mapping from DAO by means of a northbound REST
call. If the mapping had any subscribers SMRs will be sent.

Change-Id: I54a627adb1c9dc19ce4944134761979a308ded2a
Signed-off-by: Florin Coras <fcoras@ac.upc.edu>
mappingservice/api/src/main/java/org/opendaylight/lispflowmapping/interfaces/lisp/IFlowMapping.java
mappingservice/api/src/main/java/org/opendaylight/lispflowmapping/interfaces/lisp/IMapServerAsync.java
mappingservice/implementation/src/main/java/org/opendaylight/lispflowmapping/implementation/LispMappingService.java
mappingservice/implementation/src/main/java/org/opendaylight/lispflowmapping/implementation/lisp/MapServer.java
mappingservice/integrationtest/src/test/java/org/opendaylight/lispflowmapping/integrationtest/MappingServiceIntegrationTest.java
mappingservice/northbound/src/main/java/org/opendaylight/lispflowmapping/northbound/LispMappingNorthbound.java

index a127b6d6d296e6e6073b8224c609f49eaf8207bb..da3d2999b10919548c8c54c2e253a90f181f3ab6 100644 (file)
@@ -11,6 +11,7 @@ import org.opendaylight.yang.gen.v1.lispflowmapping.rev131031.MapNotify;
 import org.opendaylight.yang.gen.v1.lispflowmapping.rev131031.MapRegister;
 import org.opendaylight.yang.gen.v1.lispflowmapping.rev131031.MapReply;
 import org.opendaylight.yang.gen.v1.lispflowmapping.rev131031.MapRequest;
+import org.opendaylight.yang.gen.v1.lispflowmapping.rev131031.lispaddress.LispAddressContainer;
 
 /**
  * A mapping service.
@@ -26,4 +27,5 @@ public interface IFlowMapping extends IMapResolver, IMapServer {
     public MapNotify handleMapRegister(MapRegister mb);
 
     public MapReply handleMapRequest(MapRequest mr);
+    public void removeMapping(LispAddressContainer address, int maskLen);
 }
index f6df7236268d254d97423269a4828def5d849c5a..63e5f61796b46b370abda1cf48b9560baff36ccb 100644 (file)
@@ -8,10 +8,13 @@
 package org.opendaylight.lispflowmapping.interfaces.lisp;
 
 import org.opendaylight.yang.gen.v1.lispflowmapping.rev131031.MapRegister;
+import org.opendaylight.yang.gen.v1.lispflowmapping.rev131031.lispaddress.LispAddressContainer;
 
 /**
  * The async map server interface for dealing with async map register calls.
  */
 public interface IMapServerAsync extends IGeneralMapServer {
     public void handleMapRegister(MapRegister request, boolean smr, IMapNotifyHandler callback);
+    public void removeMapping(LispAddressContainer address, int maskLen, boolean smr, IMapNotifyHandler callback);
+
 }
index 9e20072c70a0d4af6a8a0f3f1b89e4b7658b16f4..049ab2c3a4b90d663bbd2244cf45abf463e26cdb 100644 (file)
@@ -240,6 +240,10 @@ public class LispMappingService implements CommandProvider, IFlowMapping, Bindin
         mapServer.addAuthenticationKey(address, maskLen, key);
     }
 
+    public void removeMapping(LispAddressContainer address, int maskLen) {
+        mapServer.removeMapping(address, maskLen, smr, this);
+    }
+
     public boolean shouldIterateMask() {
         return this.shouldIterateMask;
     }
index 6df586c8c57661263f5bc9bfae081b4f4faa81d1..e7a8628c58d65decd90fb43556131b281b935e57 100644 (file)
@@ -37,6 +37,7 @@ import org.opendaylight.yang.gen.v1.lispflowmapping.rev131031.MapRegister;
 import org.opendaylight.yang.gen.v1.lispflowmapping.rev131031.MapRequest;
 import org.opendaylight.yang.gen.v1.lispflowmapping.rev131031.eidrecords.EidRecordBuilder;
 import org.opendaylight.yang.gen.v1.lispflowmapping.rev131031.eidtolocatorrecords.EidToLocatorRecord;
+import org.opendaylight.yang.gen.v1.lispflowmapping.rev131031.eidtolocatorrecords.EidToLocatorRecordBuilder;
 import org.opendaylight.yang.gen.v1.lispflowmapping.rev131031.lispaddress.LispAddressContainer;
 import org.opendaylight.yang.gen.v1.lispflowmapping.rev131031.lispaddress.lispaddresscontainer.address.LcafKeyValue;
 import org.opendaylight.yang.gen.v1.lispflowmapping.rev131031.lispsimpleaddress.primitiveaddress.DistinguishedName;
@@ -137,30 +138,11 @@ public class MapServer extends AbstractLispComponent implements IMapServerAsync
                     }
                 }
                 boolean mappingChanged = saveRlocs(eidRecord, smr);
-
                 if (smr && mappingChanged) {
-                    HashSet<MappingServiceSubscriberRLOC> subscribers = getSubscribers(eidRecord.getLispAddressContainer(), eidRecord.getMaskLength());
-                    if (subscribers != null) {
-                        MapRequest mapRequest = buildSMR(eidRecord);
-                        LOG.trace("Built SMR packet: " + mapRequest.toString());
-                        for (MappingServiceSubscriberRLOC rloc : subscribers) {
-                            if (rloc.timedOut()) {
-                                LOG.trace("Lazy removing expired subscriber entry " + rloc.toString());
-                                subscribers.remove(rloc);
-                            } else {
-                                try {
-                                    callback.handleSMR(mapRequest, rloc.getSrcRloc());
-                                } catch (Exception e) {
-                                    LOG.error("Errors encountered while handling SMR:" + e.getStackTrace());
-                                }
-                            }
-                        }
-                        IMappingServiceKey key = MappingServiceKeyUtil.generateMappingServiceKey(eidRecord.getLispAddressContainer(),
-                                eidRecord.getMaskLength());
-                        dao.put(key, new MappingEntry<HashSet<MappingServiceSubscriberRLOC>>(SUBSCRIBERS_SUBKEY, subscribers));
-                    }
+                    HashSet<MappingServiceSubscriberRLOC> subscribers = getSubscribers(eidRecord.getLispAddressContainer(),
+                            eidRecord.getMaskLength());
+                    handleSmr(eidRecord, subscribers, callback);
                 }
-
             }
             if (!failed) {
                 MapNotifyBuilder builder = new MapNotifyBuilder();
@@ -234,6 +216,43 @@ public class MapServer extends AbstractLispComponent implements IMapServerAsync
         dao.put(mappingServiceKey, new MappingEntry<String>(PASSWORD_SUBKEY, key));
     }
 
+    public void removeMapping(LispAddressContainer address, int maskLen, boolean smr, IMapNotifyHandler callback) {
+        IMappingServiceKey mappingServiceKey = MappingServiceKeyUtil.generateMappingServiceKey(address, maskLen);
+        if (smr) {
+            HashSet<MappingServiceSubscriberRLOC> subscribers = getSubscribers(address, maskLen);
+            // mapping is removed before first SMR is sent to avoid inconsistent replies
+            dao.remove(mappingServiceKey);
+            handleSmr(new EidToLocatorRecordBuilder().setLispAddressContainer(address).
+                    setMaskLength((short) maskLen).build(), subscribers, callback);
+        } else {
+            dao.remove(mappingServiceKey);
+        }
+    }
+
+    private void handleSmr(EidToLocatorRecord record, HashSet<MappingServiceSubscriberRLOC> subscribers,
+            IMapNotifyHandler callback) {
+        if (subscribers == null) {
+            return;
+        }
+        MapRequest mapRequest = buildSMR(record);
+        LOG.trace("Built SMR packet: " + mapRequest.toString());
+        for (MappingServiceSubscriberRLOC rloc : subscribers) {
+            if (rloc.timedOut()) {
+                LOG.trace("Lazy removing expired subscriber entry " + rloc.toString());
+                subscribers.remove(rloc);
+            } else {
+                try {
+                    callback.handleSMR(mapRequest, rloc.getSrcRloc());
+                } catch (Exception e) {
+                    LOG.error("Errors encountered while handling SMR:" + e.getStackTrace());
+                }
+            }
+        }
+        IMappingServiceKey key = MappingServiceKeyUtil.generateMappingServiceKey(record.getLispAddressContainer(),
+                record.getMaskLength());
+        dao.put(key, new MappingEntry<HashSet<MappingServiceSubscriberRLOC>>(SUBSCRIBERS_SUBKEY, subscribers));
+    }
+
     public boolean shouldOverwrite() {
         return overwrite;
     }
index f18b7207e59b35b0dd4f28747f31f3b1545834bc..6df52af8d47e545ce4fb843e40cc85aa206ca3d6 100644 (file)
@@ -293,6 +293,7 @@ public class MappingServiceIntegrationTest {
     public void testNorthbound() throws Exception {
         northboundAddKey();
         northboundAddMapping();
+        northboundDeleteMapping();
         northboundRetrieveKey();
         northboundRetrieveMapping();
         northboundRetrieveSourceDestKey();
@@ -687,6 +688,48 @@ public class MappingServiceIntegrationTest {
 
     }
 
+    private void northboundDeleteMapping() throws Exception {
+        cleanUP();
+        LispIpv4Address eid = LispAFIConvertor.asIPAfiAddress("10.0.0.1");
+        int mask = 32;
+        LispIpv4Address rloc = LispAFIConvertor.asIPAfiAddress("20.0.0.2");
+        // Insert mapping in the database
+        MapRegisterBuilder mapRegister = new MapRegisterBuilder();
+        EidToLocatorRecordBuilder etlr = new EidToLocatorRecordBuilder();
+        etlr.setLispAddressContainer(LispAFIConvertor.toContainer(eid));
+        etlr.setMaskLength((short) mask);
+        etlr.setRecordTtl(254);
+        etlr.setAuthoritative(false);
+        etlr.setAction(Action.NoAction);
+        LocatorRecordBuilder record = new LocatorRecordBuilder();
+        record.setLispAddressContainer(LispAFIConvertor.toContainer(rloc));
+        record.setRouted(true);
+        record.setRlocProbed(false);
+        record.setLocalLocator(false);
+        record.setPriority((short) 1);
+        record.setWeight((short) 50);
+        record.setMulticastPriority((short) 1);
+        record.setMulticastWeight((short) 1);
+        etlr.setLocatorRecord(new ArrayList<LocatorRecord>());
+        etlr.getLocatorRecord().add(record.build());
+        mapRegister.setEidToLocatorRecord(new ArrayList<EidToLocatorRecord>());
+        mapRegister.getEidToLocatorRecord().add(etlr.build());
+        lms.handleMapRegister(mapRegister.build(), false);
+
+        // Delete mapping using NB interface. No IID used
+        URL url = createDeleteMappingIPv4URL(0, eid, mask);
+        String reply = callURL("DELETE", null, "application/json", null, url);
+
+        // Get mapping using NB interface. No IID used
+        url = createGetMappingIPv4URL(0, eid, mask);
+        reply = callURL("GET", null, "application/json", null, url);
+        JSONTokener jt = new JSONTokener(reply);
+        JSONObject json = new JSONObject(jt);
+
+        // With just one locator, locators is not a JSONArray
+        assertEquals(json.getJSONArray("locators").length(), 0);
+    }
+
     private void northboundRetrieveSourceDestMapping() throws Exception {
         cleanUP();
         org.opendaylight.yang.gen.v1.lispflowmapping.rev131031.lispsimpleaddress.primitiveaddress.Ipv4 address1 = (org.opendaylight.yang.gen.v1.lispflowmapping.rev131031.lispsimpleaddress.primitiveaddress.Ipv4) LispAFIConvertor
@@ -766,6 +809,13 @@ public class MappingServiceIntegrationTest {
         return url;
     }
 
+    private URL createDeleteMappingIPv4URL(int iid, LispIpv4Address address, int mask) throws MalformedURLException {
+        String restUrl = String.format("http://localhost:8080/lispflowmapping/nb/v2/default/%s/%d/%d/%s/%d", "mapping", iid, address.getAfi()
+                .shortValue(), address.getIpv4Address().getValue(), mask);
+        URL url = new URL(restUrl);
+        return url;
+    }
+
     private URL createPutURL(String resource) throws MalformedURLException {
 
         String restUrl = String.format("http://localhost:8080/lispflowmapping/nb/v2/default/%s", resource);
index 359373a96a260b0fee1c6ac02bd15d1823e1ef30..7ed7dfea98587da76c82a8fbd82115c4582e1cea 100644 (file)
@@ -290,6 +290,67 @@ public class LispMappingNorthbound implements ILispmappingNorthbound {
         return Response.status(Response.Status.OK).build();
     }
 
+    /**
+     * Delete a mapping from the LISP Map-Server database
+     *
+     * @param containerName
+     *            name of the container context from which the key is going to
+     *            be deleted
+     *
+     * @param afi
+     *            Address Family of the address (IPv4, IPv6 or MAC)
+     *
+     * @param address
+     *            Address of type defined by afi
+     *
+     * @param mask
+     *            Network mask length
+     *
+     * @return Text plain confirming deletion
+     *
+     *         <pre>
+     * Example:
+     *
+     * Request URL:
+     * http://localhost:8080/lispflowmapping/nb/v2/default/mapping/0/1/10.0.0.1/32
+     *
+     * </pre>
+     */
+
+    @Path("/{containerName}/mapping/{iid}/{afi}/{address}/{mask}")
+    @DELETE
+    @Consumes(MediaType.APPLICATION_JSON)
+    @StatusCodes({ @ResponseCode(code = 400, condition = "Invalid data passed"),
+            @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
+            @ResponseCode(code = 404, condition = "The containerName passed was not found"),
+            @ResponseCode(code = 500, condition = "Internal Server Error: Addition of mapping failed"),
+            @ResponseCode(code = 503, condition = "Service unavailable") })
+    public Response deleteMapping(@PathParam("containerName") String containerName, @PathParam("iid") int iid,
+            @PathParam("afi") int afi, @PathParam("address") String address, @PathParam("mask") int mask) {
+
+        handleContainerDoesNotExist(containerName);
+        authorizationCheck(containerName, Privilege.WRITE);
+
+        LispAddressGeneric eidGeneric = parseAddressURL(iid, afi, address, mask);
+        LispAddress eid;
+        try {
+            eid = LispAddressConvertorNB.convertToLispAddress(eidGeneric);
+        } catch (Exception e) {
+            throw new BadRequestException(RestMessages.INVALIDDATA.toString() + " : Address is not valid");
+        }
+
+        ILispmappingNorthbound nbService = (ILispmappingNorthbound) ServiceHelper.getInstance(ILispmappingNorthbound.class, containerName, this);
+
+        try {
+            nbService.getMappingService().removeMapping(YangTransformerNB.transformLispAddress(eid), mask);
+        } catch (Exception e) {
+            throw new InternalServerErrorException(RestMessages.INTERNALERROR.toString() + " : There was an error while deleting the key");
+        }
+
+        return Response.status(Response.Status.OK).build();
+    }
+
+
     /**
      * Retrieve a mapping from the LISP mapping system
      *