2 //=============================================================================
4 * @file SOCK_Netlink_Test.cpp
6 * Tests adding of a secondary IP-address, using linux netlink
9 * @author Robert Iakobashvili
10 * @author coroberti@gmail.com
12 //=============================================================================
15 #include "test_config.h"
17 #ifdef ACE_HAS_NETLINK
19 #include "ace/Event_Handler.h"
20 #include "ace/Reactor.h"
21 #include "ace/Log_Msg.h"
22 #include "ace/Get_Opt.h"
24 #include "ace/Netlink_Addr.h"
25 #include "ace/SOCK_Netlink.h"
27 #include "ace/OS_NS_sys_socket.h"
28 #include "ace/OS_NS_time.h"
30 #include <linux/rtnetlink.h>
34 * NETLINK SOCKET INTERFACE is a socket API communication
35 * between linux kernel and userland.
37 * Main usage of netlink communication is for communication between
38 * kernel/custom modules/drivers and userspace;
40 * In order not to force ACE-tests runners to install some driver for testing
41 * purposes, we are using here a build-in netlink interface used by linux for
42 * "routing" purposes (rtnetlink).
44 * This test is hopefully a useful example of how via netlink to add a new
45 * secondary IPv4 address to an interface and to delete it further. The
46 * example is integrated within reactive framework for IO demultiplexing.
48 * A one button test adds a new secondary IP-address to a loopback
49 * interface and deletes it. Even if the address added remains, this shall no
50 * cause any damage. In any case the lifetime of a secondary ip is limited
51 * till the next reboot. You may wish to run the test with -d option (not to
52 * make an address cleanup after addtion) and see it by 'ip addr' command.
53 * Further re-run of the test without -d option will cleanup the address.
55 * Please, note, that it is ok that the message "rtnetlink error message:
56 * Cannot assign requested address" will appear on your console, because first
57 * the test is trying to remove the secondary-ip and errors, if it was not before.
59 * The one-button test fails, of there is no a loopback device named "lo" on a
60 * host or the device is disabled.
62 * The same rtnetlink interface may be used to get/add/delete ip-addresses,
63 * get/add/delete routing rules, control ARP entires, control Qdisk disciplines,
64 * traffic classes and traffic filters, manage network interface configuration
66 * For more information, please, read man pages:
67 * netlink (3), netlink (7), rtnetlink (3), rtnetlink (3), rtnetlink (7) and ip (8).
69 * Some ideas for the test were borrowed from the code of iprouted2
70 * written by Alexey Kuznetsov.
72 * Command line options:
74 * -d do not cleanup the ip-address after addition (so that you can see it by the
77 * -i the name of interface to add the address
79 * -a ipv4 slash netmask bits, like "192.168.1.1/24"
84 // Generic structure for encapsulation of optional route information.
85 // It is reminiscent of sockaddr, but with sa_family replaced with attribute type.
88 unsigned short rta_len;
89 unsigned short rta_type;
95 unsigned char ifa_family;
96 unsigned char ifa_prefixlen; // The prefix length is the length of the address mask
97 unsigned char ifa_flags; // Flags: IFA_F_SECONDARY for secondary
98 // address (old alias interface), IFA_F_PERMANENT
99 // for a permanent address
100 unsigned char ifa_scope; // locality
101 int ifa_index; // Link index is the interface index in the table of interfaces.
106 __u32 nlmsg_len; // Length of message including header
107 __u16 nlmsg_type; // Message content
108 __u16 nlmsg_flags; // Additional flags
109 __u32 nlmsg_seq; // Sequence number
110 __u32 nlmsg_pid; // Sending process PID
115 // The global config params
117 static int one_button_test
= 0;
118 static char ip_slash_mask
[32];
119 static char net_dev_name
[16];
120 static int dont_cleanup_added_ip
= 0;
122 // The function returns index of an interface by its name
125 get_if_index (const char*const interface
,
131 ACE_OS::memset (&if_req
, 0, sizeof (struct ifreq
));
133 ACE_OS::strncpy (if_req
.ifr_name
,
134 static_cast<const char*> (interface
),
135 sizeof (if_req
.ifr_name
));
137 ACE_HANDLE s
= ACE_OS::socket (AF_INET
,SOCK_DGRAM
,0);
139 if (s
== ACE_INVALID_HANDLE
)
140 ACE_ERROR_RETURN ((LM_ERROR
,
142 ACE_TEXT ("get_if_index - failed on\n")
143 ACE_TEXT ("ACE_OS::socket")),
146 int result
= ACE_OS::ioctl (s
,
148 reinterpret_cast<char*> (&if_req
));
152 ACE_ERROR ((LM_ERROR
,
154 ACE_TEXT ("get_if_index:")
155 ACE_TEXT ("ioctl (get interface index)")));
159 if_index
= if_req
.ifr_ifindex
;
165 An assisting structure for passing data via routing netlink socket.
166 The idea borrowed from a great iprouted2 utility,
167 written by Alexey Kuznetsov.
179 * Contains header netlink message header of a type nlmsghdr with a
180 * following request type dependent controlling structure, which is for
181 * adding/deleting IP-addresses is of type ifaddrmsg with a following
182 * buffer, containing the data: ip-address, its length, number of netmask
185 struct Netlink_Request
187 struct nlmsghdr nhdr_
; // message header
188 struct ifaddrmsg ifa_
; // interface
194 * The handler first is trying to delete an ip-address, further
195 * to add the ip and, if successful to cleanup the address.
197 class Secondary_Ipaddr_Handler
: public ACE_Event_Handler
200 // Default constructor
201 Secondary_Ipaddr_Handler ();
204 ~Secondary_Ipaddr_Handler () override
;
206 //FUZZ: disable check_for_lack_ACE_OS
207 // Initialization. Schedules a timer to run start the business.
209 ///FUZZ: enable check_for_lack_ACE_OS
210 int open (ACE_Reactor
*const reactor
,
211 char* const ip_slash_mask
,
212 const char *const if_name
);
214 // Returns reference to netlink socket. Necessary for reactor.
215 ACE_HANDLE
get_handle () const override
;
218 * Takes care of the input. Reads the incoming messages,
219 * makes their processing.
221 int handle_input (ACE_HANDLE handle
) override
;
224 int handle_close (ACE_HANDLE handle
,
225 ACE_Reactor_Mask close_mask
) override
;
227 // Runs a state machine. Controls adding/deleting of ip-address.
228 int handle_timeout (ACE_Time_Value
const & tv
,
229 void const * arg
= 0) override
;
231 // Sends to kernel a request to add secondary ip/mask to an
233 int add_ip (char* const ip_slash_mask
,
234 const char *const if_name
);
236 // Sends to kernel a request to delete secondary ip/mask
237 // from an interface.
238 int delete_ip (char* const ip_slash_mask
,
239 const char *const if_name
);
242 * 1. We are trying to delete the ip-address, if exists.
243 * Shall be either successful, or fail, when no-ip yet.
244 * 2. Adding the ip-address, shall be successful;
245 * 3. Cleaning up the ip-address. Shall be successful as well.
257 // Returns the currect state
258 int get_state () const { return this->state_
;}
261 //FUZZ: disable check_for_lack_ACE_OS
262 // De-registers the handler from the reactor,
263 // other cleanup jobs
264 virtual int close ();
266 ///FUZZ: enable check_for_lack_ACE_OS
267 ACE_SOCK_Netlink
& socket ();
270 // Schedule two sec timer.
271 int schedule_one_sec_timer ();
273 // A workhorse for add_ip () and delete_ip ()
274 int dispatch_ip_operation (char* const ip_slash_mask
,
275 const char *const if_name
,
279 * Initializes netlink request for adding (action = true) or
280 * deleting (action = false) of a secondary ip-address/mask.
282 int init_netlink_request (char* const ip_slash_mask
,
283 const char *const if_name
,
284 Netlink_Request
& net_req
,
287 // Fills data part of Netlink_Request
288 int fill_inet_prefix (Inet_Prefix
&inet_prefix
,
289 const char*const ip_slash_netmask
);
292 * Fills routing request (operations with ip-addresses are
293 * a part of netlink routing interface).
295 void fill_rtnetlink_request (nlmsghdr
&hdr
,
302 COMMAND_TIMEOUT
= -3,
303 COMMAND_RECV_ERROR
= -2,
308 // Mark command status in handle_input ().
309 void on_recv_error () { this->command_status_
= COMMAND_RECV_ERROR
; }
310 void on_command_success () { this->command_status_
= COMMAND_SUCCESS
; }
311 void on_command_error () { this->command_status_
= COMMAND_ERROR
; }
314 ACE_SOCK_Netlink socket_
;
316 // The address of the socket.
317 ACE_Netlink_Addr address_
;
319 // Message sequence number.
322 // The request structure passed to kernel.
323 Netlink_Request netlink_request_
;
325 // ip-addr-slash-mask
331 // Buffer to receive messages. Not too large?
332 char recv_buff_
[1024];
334 // The state of the handler.
337 // The status of the command.
341 Secondary_Ipaddr_Handler::Secondary_Ipaddr_Handler ()
347 command_status_ (COMMAND_SUCCESS
)
351 Secondary_Ipaddr_Handler::~Secondary_Ipaddr_Handler ()
353 ACE_DEBUG ((LM_DEBUG
,
354 ACE_TEXT ("(%P|%t) Secondary_Ipaddr_Handler::~Secondary_Ipaddr_Handler\n")));
358 Secondary_Ipaddr_Handler::open (ACE_Reactor
*const reactor
,
359 char* const ip_slash_mask
,
360 const char *const if_name
)
363 !ip_slash_mask
|| !ACE_OS::strlen (ip_slash_mask
) ||
364 !if_name
|| !ACE_OS::strlen (if_name
))
365 ACE_ERROR_RETURN ((LM_ERROR
,
366 ACE_TEXT("(%P) Secondary_Ipaddr_Handler::open: error ")
367 ACE_TEXT("zero pointers or zero length strings used as input.\n")),
370 this->reactor (reactor
);
372 // Another option is to pass a zero pid to the address, to call open () on socket
373 // performing binding and after bind () to call getsockbyname to fill the address
375 this->address_
.set (ACE_OS::getpid (), 0);
377 if (this->socket ().open (this->address_
,
378 ACE_PROTOCOL_FAMILY_NETLINK
,
379 NETLINK_ROUTE
) == -1)
380 //FUZZ: disable check_for_lack_ACE_OS
381 ACE_ERROR_RETURN ((LM_ERROR
,
382 ACE_TEXT("(%P|%t) Secondary_Ipaddr_Handler::open: - failed\n")
383 ACE_TEXT("to initialize netlink socket bu open ().\n")),
385 //FUZZ: enable check_for_lack_ACE_OS
387 // register with the reactor for input
388 if (this->reactor ()->register_handler (this,
389 ACE_Event_Handler::READ_MASK
) == -1)
390 ACE_ERROR_RETURN ((LM_ERROR
,
391 ACE_TEXT("(%P|%t) Secondary_Ipaddr_Handler::open - ")
392 ACE_TEXT("can't register with reactor for handling input.\n")),
395 if (this->reactor ()->schedule_timer (this,
397 ACE_Time_Value::zero
) == -1)
398 ACE_ERROR_RETURN ((LM_ERROR
,
399 ACE_TEXT("(%P) Secondary_Ipaddr_Handler::open - ")
400 ACE_TEXT("can't schedule timer with reactor.\n")),
403 this->seq_
= ACE_OS::time (0);
405 ACE_OS::strncpy (this->ip_buff_
,
407 sizeof this->ip_buff_
);
409 ACE_OS::strncpy (this->if_buff_
,
411 sizeof this->if_buff_
);
417 Secondary_Ipaddr_Handler::get_handle () const
419 return this->socket_
.get_handle ();
423 Secondary_Ipaddr_Handler::handle_input (ACE_HANDLE
)
425 ACE_DEBUG ((LM_DEBUG
,
426 ACE_TEXT("(%P) Secondary_Ipaddr_Handler::handle_input - entered\n")));
431 iov
.iov_base
= this->recv_buff_
;
432 iov
.iov_len
= sizeof (this->recv_buff_
);
435 ACE_Netlink_Addr raddr
;
438 rval_bytes
= this->socket ().recv (&iov
, 1, raddr
);
441 case -1: // Complain and leave
442 ACE_ERROR_RETURN ((LM_ERROR
,
443 ACE_TEXT("(%P) Secondary_Ipaddr_Handler::handle_input - ")
444 ACE_TEXT("%p bad read\n"), ACE_TEXT("client")),
447 case 0: // Complain and leave
448 ACE_ERROR_RETURN ((LM_ERROR
,
449 ACE_TEXT("(%P) Secondary_Ipaddr_Handler::handle_input - "),
450 ACE_TEXT("eof, closing daemon (fd = %d)\n"),
451 this->get_handle ()),
455 if (raddr
.get_size () != sizeof (sockaddr_nl
))
457 this->on_recv_error ();
458 ACE_ERROR_RETURN ((LM_ERROR
,
459 ACE_TEXT("(%n %P) Secondary_Ipaddr_Handler::handle_input - ")
460 ACE_TEXT("address length not equal sockaddr_nl\n")),
464 hdr
= reinterpret_cast <nlmsghdr
*> (this->recv_buff_
);
466 if (static_cast <int> (hdr
->nlmsg_len
) != rval_bytes
)
468 this->on_recv_error ();
469 ACE_ERROR_RETURN ((LM_ERROR
,
470 ACE_TEXT("(%P) Secondary_Ipaddr_Handler::handle_input - ")
471 ACE_TEXT("size of nlmsg_len not equal received bytes\n")),
475 if (static_cast <int> (hdr
->nlmsg_pid
) != this->address_
.get_pid () || hdr
->nlmsg_seq
!= this->seq_
)
476 ACE_ERROR_RETURN ((LM_ERROR
,
477 ACE_TEXT("(%P) Secondary_Ipaddr_Handler::handle_input - ")
478 ACE_TEXT("process id or message sequence is different\n")),
481 if (hdr
->nlmsg_type
== NLMSG_ERROR
)
483 struct nlmsgerr
*err
= static_cast <struct nlmsgerr
*> (NLMSG_DATA(hdr
));
488 this->on_command_success ();
489 ACE_DEBUG ((LM_DEBUG
,
490 ACE_TEXT("(%P) Secondary_Ipaddr_Handler::handle_input - command success\n")));
494 this->on_command_error ();
495 ACE_DEBUG ((LM_DEBUG
,
496 ACE_TEXT("(%P) Secondary_Ipaddr_Handler::handle_input - command informs about error\n")));
498 // some error message
499 ACE_OS::perror("rtnetlink error message: ");
508 Secondary_Ipaddr_Handler::handle_timeout (ACE_Time_Value
const &,
511 ACE_DEBUG ((LM_DEBUG
,
512 ACE_TEXT("(%P) Secondary_Ipaddr_Handler::handle_timeout - entered\n")));
514 if (this->command_status_
!= COMMAND_SUCCESS
&&
515 (this->command_status_
!= COMMAND_ERROR
&&
516 this->state_
== IP_DELETED
))
518 ACE_ERROR_RETURN ((LM_ERROR
,
519 ACE_TEXT("(%P) Secondary_Ipaddr_Handler::handle_timeout - ")
520 ACE_TEXT("previous command failed\n")),
524 this->command_status_
= COMMAND_TIMEOUT
; //invalidate command status
526 switch (this->state_
)
528 case START
: //delete the ip, if it presents
529 if (this->delete_ip (this->ip_buff_
, this->if_buff_
) == -1)
531 this->state_
= FAILED
;
532 ACE_ERROR_RETURN ((LM_ERROR
,
533 ACE_TEXT("(%P) Secondary_Ipaddr_Handler::handle_timeout - ")
534 ACE_TEXT("delete_ip failed\n")),
539 case IP_DELETED
: // add the ip
540 if (this->add_ip (this->ip_buff_
, this->if_buff_
) == -1)
542 this->state_
= FAILED
;
543 ACE_ERROR_RETURN ((LM_ERROR
,
544 ACE_TEXT("(%P) Secondary_Ipaddr_Handler::handle_timeout - ")
545 ACE_TEXT("add_ip failed\n")),
550 case IP_ADDED
: //delete added ip to make cleanup
551 if (dont_cleanup_added_ip
)
553 this->state_
= SUCCESS
;
558 if (this->delete_ip (this->ip_buff_
, this->if_buff_
) == -1)
560 this->state_
= FAILED
;
561 ACE_ERROR_RETURN ((LM_ERROR
,
562 ACE_TEXT("(%P) Secondary_Ipaddr_Handler::handle_timeout - ")
563 ACE_TEXT("delete_ip failed\n")),
570 this->state_
= SUCCESS
;
577 this->schedule_one_sec_timer ();
583 Secondary_Ipaddr_Handler::handle_close (ACE_HANDLE
,
586 ACE_DEBUG ((LM_DEBUG
,
587 ACE_TEXT("(%P|%t) Secondary_Ipaddr_Handler::handle_close\n")));
593 Secondary_Ipaddr_Handler::close ()
595 ACE_DEBUG ((LM_DEBUG
,
596 ACE_TEXT("(%P) Secondary_Ipaddr_Handler::close\n")));
598 if (this->reactor ())
600 this->reactor ()->remove_handler (this,
601 ACE_Event_Handler::ALL_EVENTS_MASK
|
602 ACE_Event_Handler::DONT_CALL
);
604 this->reactor ()->cancel_timer (this);
612 Secondary_Ipaddr_Handler::schedule_one_sec_timer ()
614 const ACE_Time_Value
one_sec (1, 0);
616 if (this->reactor ()->schedule_timer (this,
619 ACE_ERROR_RETURN ((LM_ERROR
,
620 ACE_TEXT("(%P) Secondary_Ipaddr_Handler::schedule_one_sec_timer - ")
621 ACE_TEXT("can't schedule timer with reactor.\n")),
627 Secondary_Ipaddr_Handler::socket ()
629 return this->socket_
;
633 Secondary_Ipaddr_Handler::fill_inet_prefix (
634 Inet_Prefix
&inet_prefix
,
635 const char*const ip_slash_netmask
)
637 ACE_OS::memset (&inet_prefix
, 0, sizeof inet_prefix
);
638 char* slash
= const_cast <char *> (ACE_OS::strchr (ip_slash_netmask
, '/'));
640 *slash
= '\0'; // The idea from Igor Potulnitsky
642 inet_prefix
.family
= AF_INET
; // another option is AF_UNSPEC
643 inet_prefix
.bytelen
= 4;
644 inet_prefix
.bitlen
= -1;
647 ACE_OS::strncpy (ip_buff
, ip_slash_netmask
, sizeof (ip_buff
));
649 char* to_search
= ip_buff
, *dot
= 0;
651 for (int i
= 0; i
< 4; i
++)
655 dot
= ACE_OS::strchr (to_search
, '.');
656 if (!dot
|| !ACE_OS::strlen (to_search
))
661 int num
= ACE_OS::atoi (to_search
);
662 if (num
< 0 || num
> 255)
665 ((u_char
*) &inet_prefix
.data
)[i
] = (u_char
)num
;
671 inet_prefix
.bitlen
= 32; // AF_INET: 32
676 mask_len
= ACE_OS::atoi (slash
+ 1);
678 inet_prefix
.bitlen
= mask_len
;
685 Secondary_Ipaddr_Handler::fill_rtnetlink_request (
691 // points to the end of the aligned header
692 struct rtattr
*rta
= reinterpret_cast <struct rtattr
*> (((reinterpret_cast <char*>(&hdr
)) + NLMSG_ALIGN (hdr
.nlmsg_len
)));
694 rta
->rta_type
= type
;
695 rta
->rta_len
= RTA_LENGTH (data_length
);
696 ACE_OS::memcpy (RTA_DATA(rta
), data
, data_length
);
697 hdr
.nlmsg_len
= NLMSG_ALIGN (hdr
.nlmsg_len
) + RTA_LENGTH (data_length
);
701 Secondary_Ipaddr_Handler::dispatch_ip_operation (
702 char* const ip_slash_mask
,
703 const char *const if_name
,
706 if (this->init_netlink_request (ip_slash_mask
,
708 this->netlink_request_
,
710 ACE_ERROR_RETURN ((LM_ERROR
,
711 "Secondary_Ipaddr_Handler::ip_operation - "
712 "init_netlink_request () failed.\n"),
715 this->netlink_request_
.nhdr_
.nlmsg_seq
= ++this->seq_
;
716 this->netlink_request_
.nhdr_
.nlmsg_flags
|= NLM_F_ACK
;
720 static_cast <void*> (&this->netlink_request_
.nhdr_
),
721 this->netlink_request_
.nhdr_
.nlmsg_len
724 ACE_Netlink_Addr addr_send
;
725 addr_send
.set (0, 0);
727 if (this->socket ().send (&iov_send
,
730 ACE_ERROR_RETURN ((LM_ERROR
,
731 ACE_TEXT("Secondary_Ipaddr_Handler::ip_operation - ")
732 ACE_TEXT("send of request failed with errno %d.\n"),
739 Secondary_Ipaddr_Handler::delete_ip (
740 char* const ip_slash_mask
,
741 const char *const if_name
)
743 if (this->dispatch_ip_operation (
747 ACE_ERROR_RETURN ((LM_ERROR
,
748 ACE_TEXT("(%P) Secondary_Ipaddr_Handler::delete_ip - ")
749 ACE_TEXT("dispatch_ip_operation() failed.\n")),
755 Secondary_Ipaddr_Handler::add_ip (
756 char* const ip_slash_mask
,
757 const char *const if_name
)
759 if (this->dispatch_ip_operation (ip_slash_mask
,
762 ACE_ERROR_RETURN ((LM_ERROR
,
763 ACE_TEXT("(%P) Secondary_Ipaddr_Handler::add_ip - ")
764 ACE_TEXT("dispatch_ip_operation() failed.\n")),
770 Secondary_Ipaddr_Handler::init_netlink_request (
771 char* const ip_slash_netmask
,
772 const char *const if_name
,
773 Netlink_Request
& net_req
,
776 ACE_OS::memset (&net_req
, 0, sizeof(net_req
));
778 // fill the request header
779 net_req
.nhdr_
.nlmsg_len
=
780 NLMSG_LENGTH (sizeof(struct ifaddrmsg
));
781 net_req
.nhdr_
.nlmsg_flags
= NLM_F_REQUEST
;
782 net_req
.nhdr_
.nlmsg_type
= action
? RTM_NEWADDR
: RTM_DELADDR
;
783 net_req
.ifa_
.ifa_family
= AF_INET
;
785 int interface_index
= -1;
786 if (get_if_index (if_name
,
787 interface_index
) == -1 || interface_index
< 0)
789 ACE_OS::fprintf (stderr
, "get_if_index () - failed\n");
792 net_req
.ifa_
.ifa_index
= interface_index
;
794 Inet_Prefix local_prefix
;
796 if (fill_inet_prefix (local_prefix
,
797 ip_slash_netmask
) == -1)
799 ACE_OS::fprintf (stderr
, "fill_inet_prefix () - failed\n");
803 fill_rtnetlink_request (net_req
.nhdr_
,
806 local_prefix
.bytelen
);
808 net_req
.ifa_
.ifa_prefixlen
= local_prefix
.bitlen
; // number of bits in netmask
809 net_req
.ifa_
.ifa_scope
= 0;
814 static int run_test (char*const ip_slash_netmask
,
815 const char*const if_name
)
817 Secondary_Ipaddr_Handler sec_ip_handler
;
819 if (sec_ip_handler
.open (ACE_Reactor::instance (),
823 ACE_ERROR_RETURN ((LM_ERROR
,
824 ACE_TEXT("(%P) SOCK_Netlink_Test - run_test () failed ")
825 ACE_TEXT("due to sec_ip_handler.open () error.\n")),
828 ACE_Time_Value
wait_time (4, 0);
830 ACE_Reactor::instance()->run_reactor_event_loop (wait_time
);
832 if (sec_ip_handler
.get_state () != Secondary_Ipaddr_Handler::SUCCESS
)
839 parse_args (int argc
, ACE_TCHAR
*argv
[])
841 if (argc
== 1) // one button test
847 ACE_OS::memset (ip_slash_mask
, 0, sizeof ip_slash_mask
);
848 ACE_OS::memset (net_dev_name
, 0, sizeof net_dev_name
);
850 ACE_Get_Opt
get_opt (argc
, argv
, ACE_TEXT ("a:di:"));
851 int c
= 0, ip_len
= 0, if_len
= 0;
852 while ((c
= get_opt ()) != EOF
)
856 case 'a': // ip_slash_netmask_bits
857 ACE_OS::strcpy (ip_slash_mask
,
858 reinterpret_cast <const char*> (get_opt
.opt_arg ()));
860 if (! (ip_len
= ACE_OS::strlen (ip_slash_mask
)))
862 ACE_ERROR ((LM_ERROR
,
863 ACE_TEXT("%s, -a should be followed by a dotted ipv4 addr slash netmask bits.\n")
864 ACE_TEXT("Example: \"-a 192.168.1.1/24\" .\n"),
865 ACE_TEXT("SOCK_Netlink_Test")));
871 dont_cleanup_added_ip
= 1;
874 case 'i': // name of the interface
875 ACE_OS::strcpy (net_dev_name
,
876 reinterpret_cast <const char*> (get_opt
.opt_arg ()));
877 if (! (if_len
= ACE_OS::strlen (net_dev_name
)))
879 ACE_ERROR ((LM_ERROR
,
880 ACE_TEXT("%s, -i should be followed by a valid name of network interface.\n"),
881 ACE_TEXT("SOCK_Netlink_Test")));
891 if ((ip_len
== 0 && if_len
) || (ip_len
&& if_len
== 0))
893 ACE_ERROR_RETURN ((LM_ERROR
,
894 ACE_TEXT("%s - error: both options -a and -i should be provided.\n"),
895 ACE_TEXT("SOCK_Netlink_Test")),
898 else if (ip_len
== 0 && if_len
== 0)
906 #define DEFAULT_IP_SLASH_MASK "192.168.1.100/24"
907 #define DEFAULT_NET_DEVICE_NAME "lo"
910 run_main (int argc
, ACE_TCHAR
*argv
[])
912 ACE_START_TEST (ACE_TEXT ("SOCK_Netlink_Test"));
914 if (ACE_OS::geteuid ())
917 ACE_TEXT ("Process has no superuser priveleges. ")
918 ACE_TEXT ("Unable to run this test.\n")));
922 if (::parse_args (argc
, argv
) == -1)
929 ACE_OS::strcpy (ip_slash_mask
,
930 DEFAULT_IP_SLASH_MASK
);
931 ACE_OS::strcpy (net_dev_name
,
932 DEFAULT_NET_DEVICE_NAME
);
936 if ((rval
= run_test (ip_slash_mask
,
939 ACE_DEBUG ((LM_ERROR
,
940 ACE_TEXT ("run_test() failed with rval returned %d. "),
951 #else /* ACE_HAS_NETLINK*/
954 run_main (int, ACE_TCHAR
*[])
956 ACE_START_TEST (ACE_TEXT ("SOCK_Netlink_Test"));
959 ACE_TEXT("(%P|%t|%T) \"SOCK_Netlink_Test\" main() - ")
960 ACE_TEXT("Linux netlink socket support not configured.\n")
961 ACE_TEXT("#define ACE_HAS_NETLINK = 1 in your config.h ")
962 ACE_TEXT("file to enable and run the process as a superuser.\n")));
969 #endif /* ACE_HAS_NETLINK*/