Skip to content
Snippets Groups Projects
Commit b8d65761 authored by Reiner Hauser's avatar Reiner Hauser
Browse files

Allow to dynamically allocate a unique multicast address.

The OKS value of the multicast address is allowed to be * instead of
a real IP address. In this case the following procedure is used to allocate a
unique MC address across all partitions. The network/netmask part of the string
should still be defined, e.g. */10.149.0.0/255.255.0.0.

The allocate_multicast_address() method of NameService should be called by a
single application in the partition (typically the HLT supervisor). It will
first iterate over all existing IS objects of type 'MultiCastGroup' in the
RunParams IS server of the initial partition. If it finds an entry which
matches its own partition, the multicast address from this object will be
used. This means that MC groups will be stable as long as the initial partition
is up and running.

If the method does not find an entry, it will try to insert a new object
which contains the multicast address as a string in its name. This guarantees
the uniqueness of the object and therefore address. The method will loop over
a range of pre-defined multicast address until insertion succeeds. If the range
is exhausted an exception CannotAllocateMulticast is thrown.

As a final step either the static or dynamically allocated address and network
are published in the local partition in all DFConfig IS servers as an object
with the fixed name 'MultiCastAddress'.

The lookup_multicast_address() method simply looks up the latter object in its
appropriate DFConfig IS server and returns it.

Note that the IS object contains both the partition name and the network part, but
the latter should always be taken straight from OKS for purposes of configuration.
The IS object simply contains it as auxilliary information.
parent 0d193c1e
No related branches found
No related tags found
No related merge requests found
...@@ -41,6 +41,13 @@ namespace daq { ...@@ -41,6 +41,13 @@ namespace daq {
((std::string)m_name) ((std::string)m_name)
) )
ERS_DECLARE_ISSUE_BASE(asyncmsg,
CannotAllocateMulticast,
Issue,
"Cannot allocate multicast address",
ERS_EMPTY,
ERS_EMPTY)
namespace asyncmsg { namespace asyncmsg {
...@@ -106,16 +113,42 @@ namespace daq { ...@@ -106,16 +113,42 @@ namespace daq {
/** \brief Resolve a single specific application. /** \brief Resolve a single specific application.
* *
* \param[in] Resolves exactly one specific remote applications. * \param[in] name Resolves exactly one specific remote applications with this name.
* *
* \throws daq::asyncmsg::CannotResolve, IS exceptions * \throws daq::asyncmsg::CannotResolve, IS exceptions
*/ */
boost::asio::ip::tcp::endpoint resolve(const std::string& name) const; boost::asio::ip::tcp::endpoint resolve(const std::string& name) const;
/** \brief A helper method to parse a string of the form network/netmask. /**
* \brief Allocate the multicast address for the partition.
*
* \param[in] addr The string representation of the address; can be a full IP address or '*'.
* \param[in] network The string representation of the network to use for multicast.
* \returns The allocated multicast address.
* \throws daq::asyncmsg::CannotAllocateMulticast, daq::asyncmsg::InvalidISServer
*
* Only one application per partition should call this. If the 'addr' parameter contains
* a '*', the multicast address will be dynamically allocated in such a way that it
* is unique per installation and across partitions (e.g. in Point 1).
*/
std::string allocate_multicast_address(const std::string& addr, const std::string& network);
/** \brief Find the multicast address for the partition.
* *
* \returns A string containing the IP addresses usable by boost::asio.
*
* \throws daq::asyncmsg::CannotResolve
*
* Applications who need the multicast address of the partition should call this with the
* 'addr' taken from OKS. If 'addr' is '*' the multicast address will be dynamically looked up.
*/ */
std::string lookup_multicast_address(const std::string& addr) const;
/** typedef for readability, a 2-tuple of IP addresses representing network/netmask. */
typedef std::tuple<boost::asio::ip::address,boost::asio::ip::address> Network; typedef std::tuple<boost::asio::ip::address,boost::asio::ip::address> Network;
/** \brief A helper method to parse a string of the form network/netmask.
*/
static Network parse_address_network(const std::string& network); static Network parse_address_network(const std::string& network);
/** \brief A helper method to find the local interface matching netmask. /** \brief A helper method to find the local interface matching netmask.
......
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
<!ATTLIST info <!ATTLIST info
name CDATA #REQUIRED name CDATA #REQUIRED
type CDATA #REQUIRED type CDATA #REQUIRED
num-of-includes CDATA #REQUIRED
num-of-items CDATA #REQUIRED num-of-items CDATA #REQUIRED
oks-format CDATA #FIXED "schema" oks-format CDATA #FIXED "schema"
oks-version CDATA #REQUIRED oks-version CDATA #REQUIRED
...@@ -50,7 +49,6 @@ ...@@ -50,7 +49,6 @@
range CDATA "" range CDATA ""
format (dec|hex|oct) "dec" format (dec|hex|oct) "dec"
is-multi-value (yes|no) "no" is-multi-value (yes|no) "no"
multi-value-implementation (list|vector) "list"
init-value CDATA "" init-value CDATA ""
is-not-null (yes|no) "no" is-not-null (yes|no) "no"
> >
...@@ -64,7 +62,6 @@ ...@@ -64,7 +62,6 @@
is-composite (yes|no) #REQUIRED is-composite (yes|no) #REQUIRED
is-exclusive (yes|no) #REQUIRED is-exclusive (yes|no) #REQUIRED
is-dependent (yes|no) #REQUIRED is-dependent (yes|no) #REQUIRED
multi-value-implementation (list|vector) "list"
> >
<!ELEMENT method (method-implementation*)> <!ELEMENT method (method-implementation*)>
<!ATTLIST method <!ATTLIST method
...@@ -81,7 +78,12 @@ ...@@ -81,7 +78,12 @@
<oks-schema> <oks-schema>
<info name="" type="" num-of-includes="0" num-of-items="1" oks-format="schema" oks-version="oks-06-06-07 built &quot;May 2 2013&quot;" created-by="rhauser" created-on="msu-pc7.cern.ch" creation-time="20130502T084342" last-modified-by="rhauser" last-modified-on="msu-pc7.cern.ch" last-modification-time="20130502T084544"/> <info name="" type="" num-of-items="2" oks-format="schema" oks-version="oks-06-09-02 built &quot;Nov 2 2015&quot;" created-by="rhauser" created-on="msu-pc7.cern.ch" creation-time="20130502T084342" last-modified-by="rhauser" last-modified-on="msu-pc7.cern.ch" last-modification-time="20151102T125421"/>
<include>
<file path="is/is.xml"/>
</include>
<class name="MsgInfo"> <class name="MsgInfo">
<superclass name="Info"/> <superclass name="Info"/>
...@@ -90,4 +92,11 @@ ...@@ -90,4 +92,11 @@
<attribute name="Port" description="Port number" type="u16" is-not-null="yes"/> <attribute name="Port" description="Port number" type="u16" is-not-null="yes"/>
</class> </class>
<class name="MultiCastGroup">
<superclass name="Info"/>
<attribute name="Partition" description="The name of the partition where this multicast group is used." type="string" is-not-null="yes"/>
<attribute name="MulticastAddress" description="The address of the multicast group. It must be in the 224.*.*.* range." type="string" range="224\.[0-9]+\.[0-9]+\.[0-9]+" init-value="224.200.100.100" is-not-null="yes"/>
<attribute name="MulticastNetwork" description="The network address where multicast packages are being sent. This determines the outgoing interface and should be the network part of the " type="string" range="[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+(/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)?" init-value="10.149.0.0" is-not-null="yes"/>
</class>
</oks-schema> </oks-schema>
#ifndef MULTICASTGROUP_H
#define MULTICASTGROUP_H
#include <is/info.h>
#include <string>
#include <ostream>
// <<BeginUserCode>>
// <<EndUserCode>>
/**
*
* @author generated by the IS tool
* @version 04/11/15
*/
class MultiCastGroup : public ISInfo {
public:
/**
* The name of the partition where this multicast group is used.
*/
std::string Partition;
/**
* The address of the multicast group. It must be in the 224.*.*.* range.
*/
std::string MulticastAddress;
/**
* The network address where multicast packages are being sent. This determines the outgoing interface and should be the network part of the
*/
std::string MulticastNetwork;
static const ISType & type() {
static const ISType type_ = MultiCastGroup( ).ISInfo::type();
return type_;
}
virtual std::ostream & print( std::ostream & out ) const {
ISInfo::print( out );
out << std::endl;
out << "Partition: " << Partition << "\t// The name of the partition where this multicast group is used." << std::endl;
out << "MulticastAddress: " << MulticastAddress << "\t// The address of the multicast group. It must be in the 224.*.*.* range." << std::endl;
out << "MulticastNetwork: " << MulticastNetwork << "\t// The network address where multicast packages are being sent. This determines the outgoing interface and should be the network part of the ";
return out;
}
MultiCastGroup( )
: ISInfo( "MultiCastGroup" )
{
initialize();
}
~MultiCastGroup(){
// <<BeginUserCode>>
// <<EndUserCode>>
}
protected:
MultiCastGroup( const std::string & type )
: ISInfo( type )
{
initialize();
}
void publishGuts( ISostream & out ){
out << Partition << MulticastAddress << MulticastNetwork;
}
void refreshGuts( ISistream & in ){
in >> Partition >> MulticastAddress >> MulticastNetwork;
}
private:
void initialize()
{
MulticastAddress = "224.200.100.100";
MulticastNetwork = "10.149.0.0";
// <<BeginUserCode>>
// <<EndUserCode>>
}
// <<BeginUserCode>>
// <<EndUserCode>>
};
// <<BeginUserCode>>
// <<EndUserCode>>
inline std::ostream & operator<<( std::ostream & out, const MultiCastGroup & info ) {
info.print( out );
return out;
}
#endif // MULTICASTGROUP_H
#ifndef MULTICASTGROUPNAMED_H
#define MULTICASTGROUPNAMED_H
#include <is/namedinfo.h>
#include <string>
#include <ostream>
// <<BeginUserCode>>
// <<EndUserCode>>
/**
*
* @author generated by the IS tool
* @version 04/11/15
*/
class MultiCastGroupNamed : public ISNamedInfo {
public:
/**
* The name of the partition where this multicast group is used.
*/
std::string Partition;
/**
* The address of the multicast group. It must be in the 224.*.*.* range.
*/
std::string MulticastAddress;
/**
* The network address where multicast packages are being sent. This determines the outgoing interface and should be the network part of the
*/
std::string MulticastNetwork;
static const ISType & type() {
static const ISType type_ = MultiCastGroupNamed( IPCPartition(), "" ).ISInfo::type();
return type_;
}
virtual std::ostream & print( std::ostream & out ) const {
ISNamedInfo::print( out );
out << std::endl;
out << "Partition: " << Partition << "\t// The name of the partition where this multicast group is used." << std::endl;
out << "MulticastAddress: " << MulticastAddress << "\t// The address of the multicast group. It must be in the 224.*.*.* range." << std::endl;
out << "MulticastNetwork: " << MulticastNetwork << "\t// The network address where multicast packages are being sent. This determines the outgoing interface and should be the network part of the ";
return out;
}
MultiCastGroupNamed( const IPCPartition & partition, const std::string & name )
: ISNamedInfo( partition, name, "MultiCastGroup" )
{
initialize();
}
~MultiCastGroupNamed(){
// <<BeginUserCode>>
// <<EndUserCode>>
}
protected:
MultiCastGroupNamed( const IPCPartition & partition, const std::string & name, const std::string & type )
: ISNamedInfo( partition, name, type )
{
initialize();
}
void publishGuts( ISostream & out ){
out << Partition << MulticastAddress << MulticastNetwork;
}
void refreshGuts( ISistream & in ){
in >> Partition >> MulticastAddress >> MulticastNetwork;
}
private:
void initialize()
{
MulticastAddress = "224.200.100.100";
MulticastNetwork = "10.149.0.0";
// <<BeginUserCode>>
// <<EndUserCode>>
}
// <<BeginUserCode>>
// <<EndUserCode>>
};
// <<BeginUserCode>>
// <<EndUserCode>>
inline std::ostream & operator<<( std::ostream & out, const MultiCastGroupNamed & info ) {
info.print( out );
return out;
}
#endif // MULTICASTGROUPNAMED_H
...@@ -3,10 +3,13 @@ ...@@ -3,10 +3,13 @@
#include "transport/Interface.h" #include "transport/Interface.h"
#include "MsgInfo.h" #include "MsgInfo.h"
#include "MultiCastGroup.h"
#include "MultiCastGroupNamed.h"
#include "is/infostream.h" #include "is/infostream.h"
#include "is/infodictionary.h" #include "is/infodictionary.h"
#include "is/serveriterator.h" #include "is/serveriterator.h"
#include "is/infoiterator.h"
#include <algorithm> #include <algorithm>
...@@ -346,5 +349,86 @@ namespace daq { ...@@ -346,5 +349,86 @@ namespace daq {
return boost::asio::ip::address(); return boost::asio::ip::address();
} }
std::string NameService::allocate_multicast_address(const std::string& addr, const std::string& network)
{
MultiCastGroup group;
ISInfoDictionary dict(m_partition);
if(addr == "*") {
// Find potential entry in initial partition
ISInfoIterator it(IPCPartition(), "RunParams", MultiCastGroup::type());
bool found = false;
while(it++) {
it.value(group);
if(group.Partition == m_partition.name()) {
// found our partition.
found = true;
break;
}
}
if(!found) {
// allocate a new group.
unsigned short index = 1;
std::string name_prefix = "RunParams.MultiCast-";
group.Partition = m_partition.name();
group.MulticastAddress = std::string("224.100.100.") + boost::lexical_cast<std::string>(index);
group.MulticastNetwork = network;
while(!found && index < 256) {
try {
dict.insert(name_prefix + group.MulticastAddress, group);
found = true;
} catch(...) {
// try next
index++;
}
}
}
if(!found) {
// A dynamic address was requested, but we could not allocate one...
throw CannotAllocateMulticast(ERS_HERE);
}
}
ISServerIterator servers(m_partition, m_is_server + ".*");
if(servers.entries() == 0) {
throw InvalidISServer(ERS_HERE,m_is_server);
}
while(servers++) {
// may throw
try {
dict.checkin(std::string(servers.name()) + ".MultiCastAddress", group);
} catch(ers::Issue& reason) {
throw InvalidISServer(ERS_HERE, servers.name(), reason);
}
}
return group.MulticastAddress;
}
std::string NameService::lookup_multicast_address(const std::string& addr) const
{
if(addr == "*") {
MultiCastGroupNamed group(m_partition, m_is_server + ".MultiCastAddress");
try {
group.checkout();
return group.MulticastAddress;
} catch (ers::Issue& ex) {
throw CannotResolve(ERS_HERE, addr, ex);
}
}
return addr;
}
} }
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment