XORP中的FibConfigTableSetClick::start(string& error_msg)方法开始向CLICK推送转发表,
int
FibConfigTableSetClick::start(string& error_msg)
{
if (! ClickSocket::is_enabled())//首先,在xorp中配置好click后,启动xorp之后便会在13000端口上与click建立连接,click是SOCKET的服务端,XORP是作为客户端去连接的
return (XORP_OK);
if (_is_running)
return (XORP_OK);
if (ClickSocket::start(error_msg) != XORP_OK)//xorp/fea/data_plane/control_socket/click_socket.cc:user-level上,启动click,并建立与click的socket连接,这个启动过程会读取config.boot里的参数
return (XORP_ERROR);
// Cleanup any leftover entries from previously run XORP instance
if (! fibconfig().unicast_forwarding_entries_retain_on_startup4())
delete_all_entries4();
if (! fibconfig().unicast_forwarding_entries_retain_on_startup6())
delete_all_entries6();
_is_running = true;
//
// XXX: Push the current config into the new method
//
list<Fte4> fte_list4;
if (fibconfig().get_table4(fte_list4) == XORP_OK) {
if (set_table4(fte_list4) != XORP_OK) {
XLOG_ERROR("Cannot push the current IPv4 forwarding table "
"into the FibConfigTableSetClick plugin for setting "
"the forwarding table");
}
}
#ifdef HAVE_IPV6
list<Fte6> fte_list6;
if (fibconfig().get_table6(fte_list6) == XORP_OK) {
if (set_table6(fte_list6) != XORP_OK) {
XLOG_ERROR("Cannot push the current IPv6 forwarding table "
"into the FibConfigTableSetClick plugin for setting "
"the forwarding table");
}
}
#endif // HAVE_IPV6
return (XORP_OK);
}
所以项目中click主动向xorp汇报接口信息要改的东西就很多很多了,XORP与CLICK的配合前提是在配置文件里事先写好了所有接口信息
附:这段代码启动user-level click,并与之建立socket,为上述函数做准备
int
ClickSocket::start(string& error_msg)
{
if (is_kernel_click() && !_kernel_fd.is_valid()) {
//
// Install kernel Click (if necessary)
//
if (_kernel_click_install_on_startup) {
string error_msg2;
// Load the kernel Click modules
if (load_kernel_click_modules(error_msg) != XORP_OK) {
unload_kernel_click_modules(error_msg2);
return (XORP_ERROR);
}
// Mount the Click file system
if (mount_click_file_system(error_msg) != XORP_OK) {
unload_kernel_click_modules(error_msg2);
return (XORP_ERROR);
}
}
#ifdef O_NONBLOCK
//
// Open the Click error file (for reading error messages)
//
string click_error_filename;
click_error_filename = _kernel_click_mount_directory + "/errors";
_kernel_fd = open(click_error_filename.c_str(), O_RDONLY | O_NONBLOCK);
if (!_kernel_fd.is_valid()) {
error_msg = c_format("Cannot open kernel Click error file %s: %s",
click_error_filename.c_str(),
strerror(errno));
return (XORP_ERROR);
}
#endif
}
if (is_user_click() && !_user_fd.is_valid()) {
//
// Execute the Click command (if necessary)
//
if (_user_click_command_execute_on_startup) {
// Compose the command and the arguments
string command = _user_click_command_file;
list<string> argument_list;
argument_list.push_back("-f");
argument_list.push_back(_user_click_startup_config_file);
argument_list.push_back("-p");
argument_list.push_back(c_format("%u",
_user_click_control_socket_port));
if (! _user_click_command_extra_arguments.empty()) {
list<string> l = split(_user_click_command_extra_arguments,
' ');
argument_list.insert(argument_list.end(), l.begin(), l.end());
}
if (execute_user_click_command(command, argument_list)
!= XORP_OK) {
error_msg = c_format("Could not execute the user-level Click");
return (XORP_ERROR);
}
}
//
// Open the socket
//
struct in_addr in_addr;
_user_click_control_address.copy_out(in_addr);
//
// TODO: XXX: get rid of this hackish mechanism of waiting
// pre-defined amount of time until the user-level Click program
// starts responding.
//
TimeVal max_wait_time = USER_CLICK_STARTUP_MAX_WAIT_TIME;
TimeVal curr_wait_time(0, 100000); // XXX: 100ms
TimeVal total_wait_time;
do {
//
// XXX: try-and-wait a number of times up to "max_wait_time",
// because the user-level Click program may not response
// immediately.
//
TimerList::system_sleep(curr_wait_time);
total_wait_time += curr_wait_time;
int in_progress = 0;
_user_fd = comm_connect_tcp4(&in_addr,
htons(_user_click_control_socket_port),
COMM_SOCK_BLOCKING, &in_progress);
if (_user_fd.is_valid())
break;
if (total_wait_time < max_wait_time) {
// XXX: exponentially increase the wait time
curr_wait_time += curr_wait_time;
if (total_wait_time + curr_wait_time > max_wait_time)
curr_wait_time = max_wait_time - total_wait_time;
XLOG_WARNING("Could not open user-level Click socket: %s. "
"Trying again...",
strerror(errno));
continue;
}
error_msg = c_format("Could not open user-level Click socket: %s",
strerror(errno));
terminate_user_click_command();
return (XORP_ERROR);
} while (true);
//
// Read the expected banner
//
vector<uint8_t> message;
string error_msg2;
if (force_read_message(_user_fd, message, error_msg2) != XORP_OK) {
error_msg = c_format("Could not read on startup from user-level "
"Click socket: %s", error_msg2.c_str());
terminate_user_click_command();
comm_close(_user_fd);
_user_fd.clear();
return (XORP_ERROR);
}
//
// Check the expected banner.
// The banner should look like: "Click::ControlSocket/1.1"
//
do {
string::size_type slash1, slash2, dot1, dot2;
string banner = string(reinterpret_cast<const char*>(&message[0]),
message.size());
string version;
int major, minor;
// Find the version number and check it.
slash1 = banner.find('/');
if (slash1 == string::npos) {
error_msg = c_format("Invalid user-level Click banner: %s",
banner.c_str());
goto error_label;
}
slash2 = banner.find('/', slash1 + 1);
if (slash2 != string::npos)
version = banner.substr(slash1 + 1, slash2 - slash1 - 1);
else
version = banner.substr(slash1 + 1);
dot1 = version.find('.');
if (dot1 == string::npos) {
error_msg = c_format("Invalid user-level Click version: %s",
version.c_str());
goto error_label;
}
dot2 = version.find('.', dot1 + 1);
major = atoi(version.substr(0, dot1).c_str());
if (dot2 != string::npos)
minor = atoi(version.substr(dot1 + 1, dot2 - dot1 - 1).c_str());
else
minor = atoi(version.substr(dot1 + 1).c_str());
if ((major < CLICK_MAJOR_VERSION)
|| ((major == CLICK_MAJOR_VERSION)
&& (minor < CLICK_MINOR_VERSION))) {
error_msg = c_format("Invalid user-level Click version: "
"expected at least %d.%d "
"(found %s)",
CLICK_MAJOR_VERSION, CLICK_MINOR_VERSION,
version.c_str());
goto error_label;
}
break;
error_label:
terminate_user_click_command();
comm_close(_user_fd);
_user_fd.clear();
return (XORP_ERROR);
} while (false);
//
// Add the socket to the event loop
//
if (_eventloop.add_ioevent_cb(_user_fd, IOT_READ,
callback(this, &ClickSocket::io_event))
== false) {
error_msg = c_format("Failed to add user-level Click socket "
"to EventLoop");
terminate_user_click_command();
comm_close(_user_fd);
_user_fd.clear();
return (XORP_ERROR);
}
}
return (XORP_OK);
}