Dear all,

We are revising the ALTO base protocol. One item that we are considering to
change is some clarification of the specification schema for the base
protocol. Attached is a proposed schema. The changes and their impacts are
the following:

- Change 1.

We added a new schema called object-map. The basic problem that we are
trying to solve is the "ambiguity" of JSON deserialization. Specifically,
an JSON object { "a1":"v1", "a2":"v2"} can have interpretations: it is an
object of type
object {
  String a1;
  String a2;
}
or a HashMap object from strings to strings.

Now consider the encoding of a network map:
       "map" : {
         "PID1" : {
           "ipv4" : [
             "192.0.2.0/24",
             "198.51.100.0/24"
           ]
         },
         "PID2" : {
           "ipv4": [
             "198.51.100.128/24"
           ]
         }
       }

Now if we use the first interpretation, we need to define many class types,
one for each given number of PIDs. This is too many classes. We also
considered an array like encoding:
       "map" : [
         {"PID1" : {
           "ipv4" : [
             "192.0.2.0/24",
             "198.51.100.0/24"
           ]
         }},
         {"PID2" : {
           "ipv4": [
             "198.51.100.128/24"
           ]
         }}
       }

But this reads ugly according to several. Hence, we decided to use the
current encoding. But we give a hint that the encoding is better a HashMap
(key/value store), and hence only a single class.

Suppose one uses GSON as a parser, it is quite easy to construct:
   //    Map<String, EndpointAddrGroup> map
   //      = gson.fromJson(json,
   //          new TypeToken<Map<String, EndpointAddrGroup>>()
{}.getType());

IMPACT: It does not change the data format on the wire but conceptually
cleaner.

* Change 2.

We added a new type:
   object {                  // still separate mode and type but syntax
sugar
     CostMode mode;          // to put in the same object
     CostType type;
   } CostID;

This is based on the consensus that we separate mode and type. Wendy put
the motivation of change better than I could. So here is  her words:

"Here's how I'd describe the change. Before, the cost map request &
response messages had "cost-type" and "cost-mode" fields. Now they have
nested "cost-id.type" and "cost-id.mode" fields. That should be a simple
change for any implementation.

For a full map request, the IRD has a similar straight-forward change: in
the capabilities section, the "cost-type" and "cost-mode" fields have been
replaced by the nested "cost-id.type" and "cost-id.mode" fields.

The major difference is in the IRD entry for a filtered cost map request.
Before the server listed all valid types and modes. Now the server
specifies the valid pairs. The advantage is now the client can tell which
combinations are supported. Before, the client found out the hard way.

And the primary motivation for cost-ids is to resolve that problem with
filtered cost maps. Otherwise cost-ids are syntactic sugar."

IMPACT: Existing implementations need to merge cost-mode and cost-type into
a single object, which is a very minor change.

The authors have not made the final decisions to make the changes. Any
comments are highly welcome!

Richard
// File: ALTO Schema 
// Date: 03/14/2013

//***********************************************
//** Information Resource Directory (IRD) grammar
//***********************************************
   object {
     ResourceEntry resources<0..*>;
   } InfoResourceDirectory;

   object {
     JSONString     uri;
     JSONString     media-types<1..*>;
     JSONString     accepts<0..*>;        [OPTIONAL]
     [Capabilities] capabilities;         [OPTIONAL; exact type depends 
                                           on media-type above; 
                                           [Capabilities] denote base class]
   } ResourceEntry;

   object-map {
     String -> JSONValue;        // A map object consisting of 0 to 
                                 // many entries where each entry maps
                                 //   a String to a JSONValue
   } Capabilities;           
  
   object {                        
     CostID cost-id;
   } CostMapCapabilities;    // for cost map; single CostID unless we want
                             // to return multi costs in each entry in future

   object {                  // still separate mode and type but syntax sugar
     CostMode mode;          // to put in the same object
     CostType type;
   } CostID;

   // FilteredCostMapCapabilities renamed to CostFilteringCapabilities
   // CostFilteringCapabilities also uses CostFilteringCapabilities
   // A special case of Capabilities
   object-map {
     "cost-ids"         -> CostID<0..*>;// gives an array for request to select
     "cost-constraints" -> JSONBool;
   } CostFilteringCapabilities;

   object-map {
     "prop-types"       -> EndpointPropertyType <0..*>;
   } EndpointPropertyCapabilities;

   // Example
   GET /directory HTTP/1.1
   Host: alto.example.com
   Accept: application/alto-directory+json,application/alto-error+json

   HTTP/1.1 200 OK
   Content-Length: 1472
   Content-Type: application/alto-directory+json

   {
     "resources" : [
       {
         "uri" : "http://alto.example.com/networkmap";,
         "media-types" : [ "application/alto-networkmap+json" ]
       }, {
         "uri" : "http://alto.example.com/costmap/num/routingcost";,
         "media-types" : [ "application/alto-costmap+json" ],
         "capabilities" : {
           "cost-id" : {"mode" : "numerical", "type": "routingcost"}
         }
       }, {
         "uri" : "http://alto.example.com/costmap/num/hopcount";,
         "media-types" : [ "application/alto-costmap+json" ],
         "capabilities" : {
           "cost-id" : {"mode" : "numerical", "type": "hopcount"}
         }
       }, {
         "uri" : "http://custom.alto.example.com/maps";,
         "media-types" : [
           "application/alto-networkmap+json",
           "application/alto-costmap+json"
         ],
         "accepts" : [
           "application/alto-networkmapfilter+json",
           "application/alto-costmapfilter+json"
         ]
       }, {
         "uri" : "http://alto.example.com/endpointprop/lookup";,
         "media-types" : [ "application/alto-endpointprop+json" ],
         "accepts" : [ "application/alto-endpointpropparams+json" ],
         "capabilities" : {
           "prop-types" : [ "pid" ]
         }
       }, {
         "uri" : "http://alto.example.com/endpointcost/lookup";,
         "media-types" : [ "application/alto-endpointcost+json" ],
         "accepts" : [ "application/alto-endpointcostparams+json" ],
         "capabilities" : {
           "cost-constraints" : true,
           // OLD: comment not part of message
           // "cost-modes" : [ "ordinal", "numerical" ],
           // "cost-types" : [ "routingcost", "hopcount" ]
           // Assume server will not reveal numerical of hopcount
           "cost-ids" : [ {"mode":"ordinal",  "type":"routingcost"},
                          {"mode":"numerical","type":"routingcost"}, 
                          {"mode":"ordinal",  "type":"hopcount"}
           ]
         }
       }
     ]
   }

//************************************
//** InformationResource (IR) grammar
//************************************
   object {
     InfoResourceMetaData   meta;    [OPTIONAL]
     [InfoResourceDataType] data;
   } InfoResourceEntity;

   // [InfoResourceDataType] has 4 specific types defined for now:
   // application determines the type from media-type
   //  - InfoResourceNetworkMap
   //  - InfoResourceCostMap
   //  - InfoResourceEndpointProperty
   //  - InfoResourceEndpointCostMap

   object {
   } InfoResourceMetaData;

   object {
     JSONString code;
   } ErrorResourceEntity;

//************************************
// --- IR: Network Map 
//************************************
   object {
     VersionTag     map-vtag; 
     NetworkMapData map;
   } InfoResourceNetworkMap;

   // comment: discussed an array based encoding of map, but prefer
   // the current hash based design for better readability
   // The implementation should be still straightforward:
   //  e.g., using gson:
   //    Map<String, EndpointAddrGroup> map 
   //      = gson.fromJson(json, 
   //          new TypeToken<Map<String, EndpointAddrGroup>>() {}.getType());

   object-map {
     // OLD: EndpointAddrGroup [PIDName];
     // ...
     PIDName -> EndpointAddrGroup; // A map object with each entry mapping
                                   // a PIDName to an EndpointAddrGroup
   } NetworkMapData;

   object-map {
     //EndpointPrefix [AddressType]<0..*>;
     //...
                                   // A map object with each entry mapping
                                   // an address type to an array of prefixes
     AddressType -> EndpointPrefix<0..*>;
   } EndpointAddrGroup;

   // Example
   HTTP/1.1 200 OK
   Content-Length: 255
   Content-Type: application/alto-networkmap+json

   {
     "meta" : {},
     "data" : {
       "map-vtag" : "1266506139",
       "map" : {
         "PID1" : {
           "ipv4" : [
             "192.0.2.0/24",
             "198.51.100.0/24"
           ]
         },
         "PID2" : {
           "ipv4": [
             "198.51.100.128/24"
           ]
         }
       }
     }
   }



//************************************
// --- IR: Cost Map
//************************************
   object {
     CostID      cost-id;          // comment: define cost-ids<1..*> 
                                   // for multi-d in future?
     VersionTag  map-vtag;
     CostMapData map;
   } InfoResourceCostMap;

   object-map {
     // OLD
     // DstCosts [PIDName]; 
     //...
                                   // A map object with each entry mapping
                                   // a PIDName to a DstCosts object
     PIDName   -> DstCosts; 
   } CostMapData;

   object-map DstCosts {     
     //OLD
     // JSONValue [PIDName];
     //...
                                   // A map object with each entry mapping
                                   // a PIDName to a JSONValue
     PIDName   -> JSONValue;
   };

   // Example
   HTTP/1.1 200 OK
   Content-Length: 262
   Content-Type: application/alto-costmap+json

   {
     "meta" : {},
     "data" : {
       "cost-id" : {"mode":"numerical", "type":"routingcost"},
       "map-vtag"  : "1266506139",
       "map" : {
         "PID1": { "PID1": 1,  "PID2": 5,  "PID3": 10 },
         "PID2": { "PID1": 5,  "PID2": 1,  "PID3": 15 },
         "PID3": { "PID1": 20, "PID2": 15  }
       }
     }
   }

//*************************************
// --- Request for filtered network map
//*************************************
   object {
     PIDName     pids<0..*>;
     AddressType address-types<0..*>;
   } ReqFilteredNetworkMap;

   // Example: missing address types
   POST /networkmap/filtered HTTP/1.1
   Host: custom.alto.example.com
   Content-Length: 27
   Content-Type: application/alto-networkmapfilter+json
   Accept: application/alto-networkmap+json,application/alto-error+json

   {
     "pids": [ "PID1", "PID2" ]
   }

//*************************************
// --- Request for filtered cost map
//*************************************
   object {
     CostID     cost-id;
     JSONString constraints<0..*>;   [OPTIONAL]
     PIDFilter  pids;                [OPTIONAL]
   } ReqFilteredCostMap;

   object {
     PIDName srcs<0..*>;
     PIDName dsts<0..*>;
   } PIDFilter;

   // Example
   POST /costmap/filtered HTTP/1.1
   Host: custom.alto.example.com
   Content-Type: application/alto-costmapfilter+json
   Accept: application/alto-costmap+json,application/alto-error+json

   {
     "cost-id" : {"mode":"numerical", "type":"routingcost"},
     "pids" : {
       "srcs" : [ "PID1" ],
       "dsts" : [ "PID1", "PID2", "PID3" ]
     }
   }

//*************************************
// --- Request for endpoint properties
//*************************************
   object {
     EndpointPropertyType  properties<1..*>;
     TypedEndpointAddr     endpoints<1..*>;
   } ReqEndpointProp;

   // Example
   POST /endpointprop/lookup HTTP/1.1
   Host: alto.example.com
   Content-Length: 96
   Content-Type: application/alto-endpointpropparams+json
   Accept: application/alto-endpointprop+json,application/alto-error+json

   {
     "properties" : [ "pid", "example-prop" ],
     "endpoints" : [ "ipv4:192.0.2.34", "ipv4:203.0.113.129" ]
   }

//*************************************
// IR: endpoint properties 
//*************************************
   object {
     VersionTag              map-vtag; [DEPEND on properties]
     EndpointPropertyMapData map;
   } InfoResourceEndpointProperty;

   object-map {
     // OLD:
     // EndpointProps  [TypedEndpointAddr];
     // ...
                                   // A map object with each entry mapping
                                   // a typed endpoint address to a epp object
     TypedEndpointAddr -> EndpointProps;
   } EndpointPropertyMapData;

   object-map {
     // JSONValue [EndpointPropertyType];
     // ...
                                   // A map object with each entry mapping
                                   // a property type to a JSONValue
     EndpointPropertyType -> JSONValue;
   } EndpointProps;

   // Example
   HTTP/1.1 200 OK
   Content-Length: 149
   Content-Type: application/alto-endpointprop+json

   {
     "meta" : {},
     "data": {
       "map-vtag" : "1266506139",
       "map" : {
         "ipv4:192.0.2.34"    : { "pid": "PID1", "example-prop": "1" },
         "ipv4:203.0.113.129" : { "pid": "PID3" }
       }
     }
   }

//*************************************
// --- Request for endpoint cost
//*************************************
   object {
     CostID            cost-id; // must be among capabilities or default
     JSONString        constraints<0..*>;   [OPTIONAL]
     EndpointFilter    endpoints;
   } ReqEndpointCostMap;

   object {
     TypedEndpointAddr srcs<0..*>;          [OPTIONAL]
     TypedEndpointAddr dsts<1..*>;
   } EndpointFilter;

   // Example
   POST /endpointcost/lookup HTTP/1.1
   Host: alto.example.com
   Content-Length: 195
   Content-Type: application/alto-endpointcostparams+json
   Accept: application/alto-endpointcost+json,application/alto-error+json

   {
     "cost-id" : {"mode":"ordinal", "type":"routingcost"},
     "endpoints" : {
       "srcs": [ "ipv4:192.0.2.2" ],
       "dsts": [
         "ipv4:192.0.2.89",
         "ipv4:198.51.100.34",
         "ipv4:203.0.113.45"
       ]
     }
   }

//*************************************
// -- IR: Endpoint Cost
//*************************************
   object {
     CostID              cost-id;
     EndpointCostMapData map;
   } InfoResourceEndpointCostMap;

   object-map {
     //EndpointDstCosts [TypedEndpointAddr];
     //...
                                   // A map object with each entry mapping
                                   // a typed endpoint address to a edc object
     TypedEndpointAddr -> EndpointDstCosts;
   } EndpointCostMapData;

   object-map EndpointDstCosts {        
     //JSONValue [TypedEndpointAddr];
     //...
     TypedEndpointAddr -> JSONValue;
   };

   // Example
   HTTP/1.1 200 OK
   Content-Length: 231
   Content-Type: application/alto-endpointcost+json

   {
     "meta" : {},
     "data" : {
       "cost-id" : {"mode":"ordinal", "type":"routingcost"},
       "map" : {
          "ipv4:192.0.2.2": {
          "ipv4:192.0.2.89"    : 1,
          "ipv4:198.51.100.34" : 2,
          "ipv4:203.0.113.45"  : 3
          }
       }
     }
   }




_______________________________________________
alto mailing list
[email protected]
https://www.ietf.org/mailman/listinfo/alto

Reply via email to