// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*- // vim:set sts=4 ts=8: // Copyright (c) 2001-2007 International Computer Science Institute // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software") // to deal in the Software without restriction, subject to the conditions // listed in the XORP LICENSE file. These conditions include: you must // preserve this copyright notice, and you cannot mention the copyright // holders in advertising related to the Software without their permission. // The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This // notice is a summary of the XORP LICENSE file; the license in that file is // legally binding. // $XORP: xorp/rib/parser.hh,v 1.19 2007/02/16 22:47:07 pavlin Exp $ #ifndef __RIB_PARSER_HH__ #define __RIB_PARSER_HH__ #include #include #include #include "libxorp/xorp.h" #include "libxorp/ipv4.hh" #include "libxorp/ipv4net.hh" #include "rib.hh" class Command; /** * Base class for data types available to Parser. */ class Datum { public: virtual ~Datum() {} }; class Uint32Datum : public Datum { public: Uint32Datum(const string& s) { _n = 0; for (size_t i = 0; i < s.size(); i++) { if (!xorp_isdigit(s[i])) xorp_throw0(InvalidString); _n *= 10; _n += s[i] - '0'; } } const uint32_t& get() const { return _n; } protected: uint32_t _n; }; class StringDatum : public Datum { public: StringDatum(const string& s) : _s(s) {} const string& get() const { return _s; } protected: const string _s; }; class IPv4Datum : public Datum { public: IPv4Datum(const string& s) : _ipv4(s.c_str()) {} const IPv4& get() const { return _ipv4; } protected: const IPv4 _ipv4; }; class IPv4NetDatum : public Datum { public: IPv4NetDatum(const string& s) : _ipv4net(s.c_str()) {} const IPv4Net& get() const { return _ipv4net; } protected: const IPv4Net _ipv4net; }; /** * Base class for Argument Parsers. */ class ArgumentParser { public: ArgumentParser(const string& parser_name) : _argname(parser_name) {} virtual ~ArgumentParser() {} virtual Datum* parse(const string& s) const = 0; const string& name() const { return _argname;} private: const string _argname; }; class Uint32ArgumentParser : public ArgumentParser { public: Uint32ArgumentParser() : ArgumentParser("~Uint32") {} Datum* parse(const string& str) const; }; class StringArgumentParser : public ArgumentParser { public: StringArgumentParser() : ArgumentParser("~String") {} Datum* parse(const string& str) const; }; class IPv4ArgumentParser : public ArgumentParser { public: IPv4ArgumentParser() : ArgumentParser("~IPv4") {} Datum* parse(const string& str) const; }; class IPv4NetArgumentParser : public ArgumentParser { public: IPv4NetArgumentParser() : ArgumentParser("~IPv4Net") {} Datum* parse(const string& str) const; }; class Parser { public: Parser(); ~Parser(); int parse(const string& str) const; bool add_command(Command* command); bool add_argtype(ArgumentParser* arg); private: ArgumentParser* get_argument_parser(const string& name) const; int split_into_words(const string& str, vector & words) const; char _separator; map _templates; map _argtypes; }; class Parse_error { public: Parse_error() : _str("generic error") {} Parse_error(const string& s) : _str(s) {} const string& str() const { return _str; } private: string _str; }; /** * Datum to variable binding. */ class DatumVariableBinding { public: virtual ~DatumVariableBinding() {} virtual void transfer(Datum* d) throw (Parse_error) = 0; }; class DatumUint32Binding : public DatumVariableBinding { public: virtual ~DatumUint32Binding() {} DatumUint32Binding(uint32_t& i) : _i(i) {} void transfer(Datum* d) throw (Parse_error) { Uint32Datum* id = dynamic_cast(d); if (NULL == id) throw Parse_error("Wrong type ? int decoding failed"); _i = id->get(); } private: uint32_t& _i; }; class DatumStringBinding : public DatumVariableBinding { public: virtual ~DatumStringBinding() {} DatumStringBinding(string& s) : _s(s) {} void transfer(Datum* d) throw (Parse_error) { StringDatum* id = dynamic_cast(d); if (NULL == id) throw Parse_error("Wrong type ? string decoding failed"); _s = id->get(); } private: string& _s; }; class DatumIPv4Binding : public DatumVariableBinding { public: virtual ~DatumIPv4Binding() {} DatumIPv4Binding(IPv4& ipv4) : _ipv4(ipv4) {} void transfer(Datum* d) throw (Parse_error) { IPv4Datum* id = dynamic_cast(d); if (NULL == id) throw Parse_error("Wrong type ? ipv4 decoding failed"); _ipv4 = id->get(); } private: IPv4& _ipv4; }; class DatumIPv4NetBinding : public DatumVariableBinding { public: virtual ~DatumIPv4NetBinding() {} DatumIPv4NetBinding(IPv4Net& ipv4net) : _ipv4net(ipv4net) {} void transfer(Datum* d) throw (Parse_error) { IPv4NetDatum* id = dynamic_cast(d); if (NULL == id) throw Parse_error("Wrong type ? ipv4 decoding failed"); _ipv4net = id->get(); } private: IPv4Net& _ipv4net; }; class Command { public: Command(const string& cmd_syntax, int nargs) : _syntax(cmd_syntax), _nargs(nargs), _last_arg(-1) { check_syntax(); } virtual ~Command(); virtual int execute() = 0; const string& syntax() const { return _syntax; } void set_arg(int argnum, Datum* d) throw (Parse_error); int num_args() const { return _nargs; } protected: // // Abort if number of args in syntax string does not matches // number given. // void check_syntax(); void set_last_arg(int n) { _last_arg = n; } // // Bind positional argument to Datum type so when argument n arrives, it // can be decoded into a member variable. // void bind(int n, DatumVariableBinding* b); void bind_uint32(int n, uint32_t& i); void bind_string(int n, string& s); void bind_ipv4(int n, IPv4& addr); void bind_ipv4net(int n, IPv4Net& net); DatumVariableBinding* find_binding(int n); protected: const string _syntax; const int _nargs; // Number of args before execute can be called int _last_arg; // Last argument added map _bindings; }; class TableOriginCommand : public Command { public: TableOriginCommand() : Command("table origin ~String ~Uint32", 2) { bind_string(0, _tablename); bind_uint32(1, _admin_distance); } virtual int execute() = 0; protected: string _tablename; uint32_t _admin_distance; }; class TableMergedCommand : public Command { public: TableMergedCommand() : Command("table merged ~String ~String ~String", 3) { bind_string(0, _tablename); bind_string(1, _t1); bind_string(2, _t2); } virtual int execute() = 0; protected: string _tablename; string _t1; string _t2; }; class TableExtIntCommand : public Command { public: TableExtIntCommand() : Command("table extint ~String ~String ~String", 3) { bind_string(0, _tablename); bind_string(1, _t1); bind_string(2, _t2); } virtual int execute() = 0; protected: string _tablename; string _t1; string _t2; }; class RouteAddCommand : public Command { public: RouteAddCommand() : Command("route add ~String ~IPv4Net ~IPv4 ~Uint32", 4) { bind_string(0, _tablename); bind_ipv4net(1, _net); bind_ipv4(2, _nexthop); bind_uint32(3, _metric); } virtual int execute() = 0; protected: string _tablename; IPv4Net _net; IPv4 _nexthop; uint32_t _metric; }; class RouteVifAddCommand : public Command { public: RouteVifAddCommand() : Command("route vifadd ~String ~IPv4Net ~String ~IPv4 ~Uint32", 5) { bind_string(0, _tablename); bind_ipv4net(1, _net); bind_string(2, _vifname); bind_ipv4(3, _nexthop); bind_uint32(4, _metric); } virtual int execute() = 0; protected: string _tablename; IPv4Net _net; string _vifname; IPv4 _nexthop; uint32_t _metric; }; class RouteDeleteCommand : public Command { public: RouteDeleteCommand() : Command("route delete ~String ~IPv4Net", 2) { bind_string(0, _tablename); bind_ipv4net(1, _net); } virtual int execute() = 0; protected: string _tablename; IPv4Net _net; }; class RouteVerifyCommand : public Command { public: RouteVerifyCommand() : Command( "route verify ~String ~IPv4 ~String ~IPv4 ~Uint32", 5) { bind_string(0, _type); bind_ipv4(1, _lookupaddr); bind_string(2, _ifname); bind_ipv4(3, _nexthop); bind_uint32(4, _metric); } virtual int execute() = 0; protected: string _type; // Type of result expected. string _ifname; IPv4 _lookupaddr; IPv4 _nexthop; uint32_t _metric; }; class DiscardVifCommand : public Command { public: DiscardVifCommand() : Command("vif Discard ~String ~IPv4 ~Uint32", 3) { bind_string(0, _ifname); bind_ipv4(1, _addr); bind_uint32(2, _prefix_len); } virtual int execute() = 0; protected: string _ifname; IPv4 _addr; uint32_t _prefix_len; }; class EtherVifCommand : public Command { public: EtherVifCommand() : Command("vif Ethernet ~String ~IPv4 ~Uint32", 3) { bind_string(0, _ifname); bind_ipv4(1, _addr); bind_uint32(2, _prefix_len); } virtual int execute() = 0; protected: string _ifname; IPv4 _addr; uint32_t _prefix_len; }; class LoopbackVifCommand : public Command { public: LoopbackVifCommand() : Command("vif Loopback ~String ~IPv4 ~Uint32", 3) { bind_string(0, _ifname); bind_ipv4(1, _addr); bind_uint32(2, _prefix_len); } virtual int execute() = 0; protected: string _ifname; IPv4 _addr; uint32_t _prefix_len; }; class RedistEnableCommand : public Command { public: RedistEnableCommand() : Command("redistribute enable ~String ~String", 2) { bind_string(0, _from_table); bind_string(1, _to_table); } virtual int execute() = 0; protected: string _from_table; string _to_table; }; class RedistDisableCommand : public Command { public: RedistDisableCommand() : Command("redistribute disable ~String ~String", 2) { bind_string(0, _from_table); bind_string(1, _to_table); } virtual int execute() = 0; protected: string _from_table; string _to_table; }; class AddIGPTableCommand : public Command { public: AddIGPTableCommand() : Command("add_igp_table ~String", 1) { bind_string(0, _tablename); } virtual int execute() = 0; protected: string _tablename; }; class DeleteIGPTableCommand : public Command { public: DeleteIGPTableCommand() : Command("delete_igp_table ~String", 1) { bind_string(0, _tablename); } virtual int execute() = 0; protected: string _tablename; }; class AddEGPTableCommand : public Command { public: AddEGPTableCommand() : Command("add_egp_table ~String", 1) { bind_string(0, _tablename); } virtual int execute() = 0; protected: string _tablename; }; class DeleteEGPTableCommand : public Command { public: DeleteEGPTableCommand() : Command("delete_egp_table ~String", 1) { bind_string(0, _tablename); } virtual int execute() = 0; protected: string _tablename; }; #endif // __RIB_PARSER_HH__