123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507 |
- // Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
- //
- // Permission to use, copy, modify, and/or distribute this software for any
- // purpose with or without fee is hereby granted, provided that the above
- // copyright notice and this permission notice appear in all copies.
- //
- // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
- // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
- // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
- // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- // PERFORMANCE OF THIS SOFTWARE.
- #include <stdint.h>
- #include <iostream>
- #include <vector>
- #include <map>
- #include <boost/foreach.hpp>
- #include <boost/shared_ptr.hpp>
- #include <boost/scoped_ptr.hpp>
- #include <boost/lexical_cast.hpp>
- #include <boost/algorithm/string.hpp>
- #include <cc/data.h>
- #include <asiolink/io_address.h>
- #include <dhcp6/config_parser.h>
- #include <dhcp/triplet.h>
- #include <dhcp/pool.h>
- #include <dhcp/subnet.h>
- #include <dhcp/cfgmgr.h>
- using namespace std;
- using namespace isc::data;
- using namespace isc::asiolink;
- namespace isc {
- namespace dhcp {
- typedef boost::shared_ptr<Dhcp6ConfigParser> ParserPtr;
- typedef pair<string, ConstElementPtr> ConfigPair;
- typedef std::vector<ParserPtr> ParserCollection;
- typedef Dhcp6ConfigParser* ParserFactory(const std::string& config_id);
- typedef std::map<std::string, ParserFactory*> FactoryMap;
- typedef std::map<string, uint32_t> Uint32Storage;
- /// @brief That is a map with global parameters that will be used as defaults
- Uint32Storage uint32_defaults;
- typedef std::map<string, string> StringStorage;
- StringStorage string_defaults;
- typedef std::vector<Pool6Ptr> PoolStorage;
- PoolStorage pool_defaults;
- /// @brief a dummy configuration parser
- ///
- /// It is a debugging parser. It does not configure anything,
- /// will accept any configuration and will just print it out
- /// on commit.
- class DummyParser : public Dhcp6ConfigParser {
- public:
- DummyParser(const std::string& param_name)
- :param_name_(param_name) {
- }
- virtual void build(ConstElementPtr new_config) {
- value_ = new_config;
- }
- virtual void commit() {
- // debug message. The whole DummyParser class is used only for parser
- // debugging, and is not used in production code. It is very convenient
- // to keep it around. Please do not turn this cout into logger calls
- std::cout << "Commit for token: [" << param_name_ << "] = ["
- << value_->str() << "]" << std::endl;
- }
- static Dhcp6ConfigParser* Factory(const std::string& param_name) {
- return (new DummyParser(param_name));
- }
- protected:
- std::string param_name_;
- ConstElementPtr value_;
- };
- class Uint32Parser : public Dhcp6ConfigParser {
- public:
- Uint32Parser(const std::string& param_name)
- :storage_(&uint32_defaults), param_name_(param_name) {
- }
- virtual void build(ConstElementPtr value) {
- try {
- value_ = boost::lexical_cast<uint32_t>(value->str());
- } catch (const boost::bad_lexical_cast &) {
- isc_throw(BadValue, "Failed to parse value " << value->str()
- << " as unsigned 32-bit integer.");
- }
- cout << "### storing " << param_name_ << "=" << value_ <<
- " in " << storage_ << endl;
- storage_->insert(pair<string, uint32_t>(param_name_, value_));
- }
- virtual void commit() {
- }
- static Dhcp6ConfigParser* Factory(const std::string& param_name) {
- return (new Uint32Parser(param_name));
- }
- void setStorage(Uint32Storage* storage) {
- storage_ = storage;
- }
- protected:
- Uint32Storage * storage_;
- std::string param_name_;
- uint32_t value_;
- };
- class StringParser : public Dhcp6ConfigParser {
- public:
- StringParser(const std::string& param_name)
- :storage_(&string_defaults), param_name_(param_name) {
- }
- virtual void build(ConstElementPtr value) {
- value_ = value->str();
- boost::erase_all(value_, "\"");
- storage_->insert(pair<string, string>(param_name_, value_));
- }
- virtual void commit() {
- }
- static Dhcp6ConfigParser* Factory(const std::string& param_name) {
- return (new StringParser(param_name));
- }
- void setStorage(StringStorage * storage) {
- storage_ = storage;
- }
- protected:
- StringStorage * storage_;
- std::string param_name_;
- std::string value_;
- };
- class InterfaceListConfigParser : public Dhcp6ConfigParser {
- public:
- InterfaceListConfigParser(const std::string& param_name) {
- if (param_name != "interface") {
- isc_throw(NotImplemented, "Internal error. Interface configuration "
- "parser called for the wrong parameter: " << param_name);
- }
- }
- virtual void build(ConstElementPtr value) {
- BOOST_FOREACH(ConstElementPtr iface, value->listValue()) {
- interfaces_.push_back(iface->str());
- cout << "#### Configured to listen on interface " << iface->str() << endl;
- }
- }
- virtual void commit() {
- /// @todo: Implement per interface listening. Currently always listening on all
- /// interfaces.
- }
- static Dhcp6ConfigParser* Factory(const std::string& param_name) {
- return (new InterfaceListConfigParser(param_name));
- }
- protected:
- vector<string> interfaces_;
- };
- class PoolParser : public Dhcp6ConfigParser {
- public:
- PoolParser(const std::string& /*param_name*/)
- :pools_(NULL) {
- // ignore parameter name, it is always Dhcp6/subnet6[X]/pool
- }
- void build(ConstElementPtr pools_list) {
- // setStorage() should have been called before build
- if (!pools_) {
- isc_throw(NotImplemented, "Parser logic error. No pool storage set,"
- " but pool parser asked to parse pools");
- }
- BOOST_FOREACH(ConstElementPtr text_pool, pools_list->listValue()) {
- // That should be a single pool representation. It should contain
- // text is form prefix/len or first - last. Note that spaces
- // are allowed
- string txt = text_pool->stringValue();
- // first let's remove any spaces or tabs
- boost::erase_all(txt, " ");
- boost::erase_all(txt, "\t");
- size_t pos = txt.find("/");
- if (pos != string::npos) {
- IOAddress addr("::");
- uint8_t len = 0;
- try {
- addr = IOAddress(txt.substr(0, pos));
- string num = txt.substr(pos+1);
- // it is lexical cast to int and then downcast to uint8_t
- // direct cast to uint8_t (which is really an unsigned char)
- // will result in interpreting the first digit as output
- // value and throwing exception if length written on two
- // digits (because there are extra characters left over)
- len = boost::lexical_cast<int>(num);
- } catch (...) {
- isc_throw(Dhcp6ConfigError, "Failed to parse pool "
- "definition: " << text_pool->stringValue());
- }
- cout << "#### Creating Pool6(TYPE_IA, " << addr.toText() << "/"
- << (int)len << ")" << endl;
- // using prefix/len notation
- Pool6Ptr pool(new Pool6(Pool6::TYPE_IA, addr, len));
- pools_->push_back(pool);
- continue;
- }
- pos = txt.find("-");
- if (pos != string::npos) {
- IOAddress min(txt.substr(0,pos-1));
- IOAddress max(txt.substr(pos+1));
- cout << "#### Creating Pool6(TYPE_IA, " << min.toText() << ","
- << max.toText() << ")" << endl;
- Pool6Ptr pool(new Pool6(Pool6::TYPE_IA, min, max));
- pools_->push_back(pool);
- continue;
- }
- isc_throw(Dhcp6ConfigError, "Failed to parse pool definition:"
- << text_pool->stringValue() <<
- ". Does not contain - (for min-max) nor / (prefix/len)");
- }
- }
- void setStorage(PoolStorage* storage) {
- pools_ = storage;
- }
- void commit() {}
- static Dhcp6ConfigParser* Factory(const std::string& param_name) {
- return (new PoolParser(param_name));
- }
- protected:
- PoolStorage * pools_;
- };
- /// @brief this class parses a single subnet
- class Subnet6ConfigParser : public Dhcp6ConfigParser {
- public:
- Subnet6ConfigParser(const std::string& param_name) {
- }
- void build(ConstElementPtr subnet) {
- cout << "#### Subnet6ConfigParser::build(): parsing: [" << subnet->str() << "]" << endl;
- BOOST_FOREACH(ConfigPair param, subnet->mapValue()) {
- ParserPtr parser(createSubnet6ConfigParser(param.first));
- // if this is an Uint32 parser, tell it to store the values
- // in values_, rather than in global storage
- boost::shared_ptr<Uint32Parser> uintParser =
- boost::dynamic_pointer_cast<Uint32Parser>(parser);
- if (uintParser) {
- uintParser->setStorage(&uint32_values_);
- }
- boost::shared_ptr<StringParser> stringParser =
- boost::dynamic_pointer_cast<StringParser>(parser);
- if (stringParser) {
- stringParser->setStorage(&string_values_);
- }
- boost::shared_ptr<PoolParser> poolParser =
- boost::dynamic_pointer_cast<PoolParser>(parser);
- if (poolParser) {
- poolParser->setStorage(&pools_);
- }
- parser->build(param.second);
- parsers_.push_back(parser);
- }
- // Ok, we now have subnet parsed
- }
- void commit() {
- StringStorage::const_iterator it = string_values_.find("subnet");
- cout << "#### Subnet6ConfigParser::commit() string_values_.size()="
- << string_values_.size() << endl;
- if (it == string_values_.end()) {
- isc_throw(Dhcp6ConfigError,
- "Mandatory subnet definition in subnet missing");
- }
- string subnet_txt = it->second;
- boost::erase_all(subnet_txt, " ");
- boost::erase_all(subnet_txt, "\t");
- size_t pos = subnet_txt.find("/");
- if (pos == string::npos) {
- isc_throw(Dhcp6ConfigError,
- "Invalid subnet syntax (prefix/len expected):" << it->second);
- }
- IOAddress addr(subnet_txt.substr(0, pos));
- uint8_t len = boost::lexical_cast<unsigned int>(subnet_txt.substr(pos + 1));
- Triplet<uint32_t> t1 = getParam("renew-timer");
- Triplet<uint32_t> t2 = getParam("rebind-timer");
- Triplet<uint32_t> pref = getParam("preferred-lifetime");
- Triplet<uint32_t> valid = getParam("valid-lifetime");
- cout << "#### Adding subnet " << addr.toText() << "/" << (int)len
- << " with params t1=" << t1 << ", t2=" << t2 << ", pref="
- << pref << ", valid=" << valid << endl;
- Subnet6Ptr subnet(new Subnet6(addr, len, t1, t2, pref, valid));
- CfgMgr::instance().addSubnet6(subnet);
- }
- protected:
- Dhcp6ConfigParser* createSubnet6ConfigParser(const std::string& config_id) {
- FactoryMap factories;
- factories.insert(pair<string, ParserFactory*>(
- "preferred-lifetime", Uint32Parser::Factory));
- factories.insert(pair<string, ParserFactory*>(
- "valid-lifetime", Uint32Parser::Factory));
- factories.insert(pair<string, ParserFactory*>(
- "renew-timer", Uint32Parser::Factory));
- factories.insert(pair<string, ParserFactory*>(
- "rebind-timer", Uint32Parser::Factory));
- factories.insert(pair<string, ParserFactory*>(
- "subnet", StringParser::Factory));
- factories.insert(pair<string, ParserFactory*>(
- "pool", PoolParser::Factory));
- FactoryMap::iterator f = factories.find(config_id);
- if (f == factories.end()) {
- // Used for debugging only.
- // return new DummyParser(config_id);
- isc_throw(NotImplemented,
- "Parser error: Subnet6 parameter not supported: "
- << config_id);
- }
- return (f->second(config_id));
- }
- Triplet<uint32_t> getParam(const std::string& name) {
- uint32_t value = 0;
- bool found = false;
- Uint32Storage::iterator global = uint32_defaults.find(name);
- if (global != uint32_defaults.end()) {
- value = global->second;
- found = true;
- }
- Uint32Storage::iterator local = uint32_values_.find(name);
- if (local != uint32_values_.end()) {
- value = local->second;
- found = true;
- }
- if (found) {
- return (Triplet<uint32_t>(value));
- } else {
- isc_throw(Dhcp6ConfigError, "Mandatory parameter " << name
- << " missing (no global default and no subnet-"
- << "specific value)");
- }
- }
- Uint32Storage uint32_values_;
- StringStorage string_values_;
- PoolStorage pools_;
- ParserCollection parsers_;
- };
- /// @brief this class parses list of subnets
- class Subnets6ListConfigParser : public Dhcp6ConfigParser {
- public:
- Subnets6ListConfigParser(const std::string& param_name) {
- }
- void build(ConstElementPtr subnets_list) {
- // No need to define FactoryMap here. There's only one type
- // used: Subnet6ConfigParser
- BOOST_FOREACH(ConstElementPtr subnet, subnets_list->listValue()) {
- ParserPtr parser(new Subnet6ConfigParser("subnet"));
- parser->build(subnet);
- subnets_.push_back(parser);
- }
- }
- void commit() {
- BOOST_FOREACH(ParserPtr subnet, subnets_) {
- subnet->commit();
- }
- }
- static Dhcp6ConfigParser* Factory(const std::string& param_name) {
- return (new Subnets6ListConfigParser(param_name));
- }
- ParserCollection subnets_;
- };
- /// @brief creates global parsers
- ///
- /// This method creates global parsers that parse global parameters, i.e.
- /// those that take format of Dhcp6/param1, Dhcp6/param2 and so forth.
- Dhcp6ConfigParser* createGlobalDhcp6ConfigParser(const std::string& config_id) {
- FactoryMap factories;
- //
- factories.insert(pair<string, ParserFactory*>(
- "preferred-lifetime", Uint32Parser::Factory));
- factories.insert(pair<string, ParserFactory*>(
- "valid-lifetime", Uint32Parser::Factory));
- factories.insert(pair<string, ParserFactory*>(
- "renew-timer", Uint32Parser::Factory));
- factories.insert(pair<string, ParserFactory*>(
- "rebind-timer", Uint32Parser::Factory));
- factories.insert(pair<string, ParserFactory*>(
- "interface", InterfaceListConfigParser::Factory));
- factories.insert(pair<string, ParserFactory*>(
- "subnet6", Subnets6ListConfigParser::Factory));
- factories.insert(pair<string, ParserFactory*>(
- "version", StringParser::Factory));
- FactoryMap::iterator f = factories.find(config_id);
- if (f == factories.end()) {
- // Used for debugging only.
- // return new DummyParser(config_id);
- isc_throw(NotImplemented,
- "Parser error: Global configuration parameter not supported: "
- << config_id);
- }
- return (f->second(config_id));
- }
- void
- configureDhcp6Server(Dhcpv6Srv& server, ConstElementPtr config_set) {
- if (!config_set) {
- isc_throw(Dhcp6ConfigError,
- "Null pointer is passed to configuration parser");
- }
- ParserCollection parsers;
- try {
- BOOST_FOREACH(ConfigPair config_pair, config_set->mapValue()) {
- ParserPtr parser(createGlobalDhcp6ConfigParser(config_pair.first));
- parser->build(config_pair.second);
- parsers.push_back(parser);
- }
- } catch (const Dhcp6ConfigError& ex) {
- throw; // simply rethrowing it
- } catch (const isc::Exception& ex) {
- isc_throw(Dhcp6ConfigError, "Server configuration failed: " <<
- ex.what());
- }
- try {
- BOOST_FOREACH(ParserPtr parser, parsers) {
- parser->commit();
- }
- } catch (...) {
- isc_throw(Dhcp6ConfigError, "Unrecoverable error: "
- "a configuration parser threw in commit");
- }
- }
- }; // end of isc::dhcp namespace
- }; // end of isc namespace
|