On 02/25/2010 09:51 AM, Ben Greear wrote:
On 02/25/2010 05:59 AM, Eric S. Johnson wrote:

There is a else clause in

fea/data_plane/ifconfig/ifconfig_set_netlink_socket.cc

that works (or at least doesn't have vrrp process die)

#ifndef HAVE_NETLINK_SOCKETS_SET_FLAGS_IS_BROKEN

        code that uses netlink and doesn't work and makes vrrp go south

#else // HAVE_NETLINK_SOCKETS_SET_FLAGS_IS_BROKEN

      //
      // XXX: a work-around in case the kernel doesn't support setting
      // the flags on an interface by using netlink.
      // In this case, the work-around is to use ioctl(). Sigh...
      //
        code that use a ioctl instead and seems to work.

#endif

Can you try the attached patch and see if it properly detects the failure
(at runtime) and takes proper action to use the ioctl?  You should see one
complaint in the logs about having to switch to ioctl, but after that it
should not complain if I wrote the code correctly.

                    error_msg = c_format("ERROR:  Settting interface status using 
netlink failed"
                                         " on: %s.  Will try to use ioctl method 
instead.",
                                         ifname.c_str());

This is compile tested only.

Thanks,
Ben

--
Ben Greear <[email protected]>
Candela Technologies Inc  http://www.candelatech.com

diff --git a/fea/data_plane/ifconfig/ifconfig_set_netlink_socket.cc 
b/fea/data_plane/ifconfig/ifconfig_set_netlink_socket.cc
index 59ab6f9..46f8b3d 100644
--- a/fea/data_plane/ifconfig/ifconfig_set_netlink_socket.cc
+++ b/fea/data_plane/ifconfig/ifconfig_set_netlink_socket.cc
@@ -540,101 +540,134 @@ IfConfigSetNetlinkSocket::set_interface_status(const 
string& ifname,
     else
        interface_flags &= ~IFF_UP;
 
-#ifndef HAVE_NETLINK_SOCKETS_SET_FLAGS_IS_BROKEN
-    static const size_t        buffer_size = sizeof(struct nlmsghdr)
-       + sizeof(struct ifinfomsg) + 2*sizeof(struct rtattr) + 512;
-    union {
-       uint8_t         data[buffer_size];
-       struct nlmsghdr nlh;
-    } buffer;
-    struct nlmsghdr*   nlh = &buffer.nlh;
-    struct sockaddr_nl snl;
-    struct ifinfomsg*  ifinfomsg;
-    NetlinkSocket&     ns = *this;
-    int                        last_errno = 0;
-
-    memset(&buffer, 0, sizeof(buffer));
-
-    // Set the socket
-    memset(&snl, 0, sizeof(snl));
-    snl.nl_family = AF_NETLINK;
-    snl.nl_pid    = 0;         // nl_pid = 0 if destination is the kernel
-    snl.nl_groups = 0;
-
-    //
-    // Set the request
-    //
-    nlh->nlmsg_len = NLMSG_LENGTH(sizeof(*ifinfomsg));
-    nlh->nlmsg_type = RTM_NEWLINK;
-    nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE | 
NLM_F_ACK;
-    nlh->nlmsg_seq = ns.seqno();
-    nlh->nlmsg_pid = ns.nl_pid();
-    ifinfomsg = static_cast<struct ifinfomsg*>(NLMSG_DATA(nlh));
-    ifinfomsg->ifi_family = AF_UNSPEC;
-    ifinfomsg->ifi_type = IFLA_UNSPEC;
-    ifinfomsg->ifi_index = if_index;
-    ifinfomsg->ifi_flags = interface_flags;
-    ifinfomsg->ifi_change = 0xffffffff;
-
-    if (NLMSG_ALIGN(nlh->nlmsg_len) > sizeof(buffer)) {
-       XLOG_FATAL("AF_NETLINK buffer size error: %u instead of %u",
-                  XORP_UINT_CAST(sizeof(buffer)),
-                  XORP_UINT_CAST(NLMSG_ALIGN(nlh->nlmsg_len)));
-    }
-    nlh->nlmsg_len = NLMSG_ALIGN(nlh->nlmsg_len);
-
-    if (ns.sendto(&buffer, nlh->nlmsg_len, 0,
-                 reinterpret_cast<struct sockaddr*>(&snl), sizeof(snl))
-       != (ssize_t)nlh->nlmsg_len) {
-       error_msg = c_format("Cannot set the interface flags to 0x%x on "
-                            "interface %s: %s",
-                            interface_flags, ifname.c_str(), strerror(errno));
-       return (XORP_ERROR);
-    }
-    if (NlmUtils::check_netlink_request(_ns_reader, ns, nlh->nlmsg_seq,
-                                       last_errno, error_msg)
-       != XORP_OK) {
-       error_msg = c_format("Cannot set the interface flags to 0x%x on "
-                            "interface %s: %s",
-                            interface_flags, ifname.c_str(),
-                            error_msg.c_str());
-       return (XORP_ERROR);
-    }
-
-    return (XORP_OK);
-
-#else // HAVE_NETLINK_SOCKETS_SET_FLAGS_IS_BROKEN
-    //
-    // XXX: a work-around in case the kernel doesn't support setting
-    // the flags on an interface by using netlink.
-    // In this case, the work-around is to use ioctl(). Sigh...
-    //
     struct ifreq ifreq;
+    int s = -1;
+
+    // Evidently, some older systems don't return errors, but just do not
+    // actually work.
+    static int netlink_set_status_works = -1;
+
+    if (netlink_set_status_works != 0) {
+       static const size_t     buffer_size = sizeof(struct nlmsghdr)
+           + sizeof(struct ifinfomsg) + 2*sizeof(struct rtattr) + 512;
+       union {
+           uint8_t             data[buffer_size];
+           struct nlmsghdr     nlh;
+       } buffer;
+       struct nlmsghdr*        nlh = &buffer.nlh;
+       struct sockaddr_nl      snl;
+       struct ifinfomsg*       ifinfomsg;
+       NetlinkSocket&  ns = *this;
+       int                     last_errno = 0;
+
+       memset(&buffer, 0, sizeof(buffer));
+
+       // Set the socket
+       memset(&snl, 0, sizeof(snl));
+       snl.nl_family = AF_NETLINK;
+       snl.nl_pid    = 0;              // nl_pid = 0 if destination is the 
kernel
+       snl.nl_groups = 0;
 
-    UNUSED(if_index);
+       //
+       // Set the request
+       //
+       nlh->nlmsg_len = NLMSG_LENGTH(sizeof(*ifinfomsg));
+       nlh->nlmsg_type = RTM_NEWLINK;
+       nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE | 
NLM_F_ACK;
+       nlh->nlmsg_seq = ns.seqno();
+       nlh->nlmsg_pid = ns.nl_pid();
+       ifinfomsg = static_cast<struct ifinfomsg*>(NLMSG_DATA(nlh));
+       ifinfomsg->ifi_family = AF_UNSPEC;
+       ifinfomsg->ifi_type = IFLA_UNSPEC;
+       ifinfomsg->ifi_index = if_index;
+       ifinfomsg->ifi_flags = interface_flags;
+       ifinfomsg->ifi_change = 0xffffffff;
+
+       if (NLMSG_ALIGN(nlh->nlmsg_len) > sizeof(buffer)) {
+           XLOG_FATAL("AF_NETLINK buffer size error: %u instead of %u",
+                      XORP_UINT_CAST(sizeof(buffer)),
+                      XORP_UINT_CAST(NLMSG_ALIGN(nlh->nlmsg_len)));
+       }
+       nlh->nlmsg_len = NLMSG_ALIGN(nlh->nlmsg_len);
+
+       if (ns.sendto(&buffer, nlh->nlmsg_len, 0,
+                     reinterpret_cast<struct sockaddr*>(&snl), sizeof(snl))
+           != (ssize_t)nlh->nlmsg_len) {
+           error_msg = c_format("Cannot set the interface flags to 0x%x on "
+                                "interface %s: %s",
+                                interface_flags, ifname.c_str(), 
strerror(errno));
+           return (XORP_ERROR);
+       }
+       if (NlmUtils::check_netlink_request(_ns_reader, ns, nlh->nlmsg_seq,
+                                           last_errno, error_msg)
+           != XORP_OK) {
+           error_msg = c_format("Cannot set the interface flags to 0x%x on "
+                                "interface %s: %s",
+                                interface_flags, ifname.c_str(),
+                                error_msg.c_str());
+           return (XORP_ERROR);
+       }
 
-    int s = socket(AF_INET, SOCK_DGRAM, 0);
-    if (s < 0) {
-       XLOG_FATAL("Could not initialize IPv4 ioctl() socket");
+       if (netlink_set_status_works == -1) {
+           netlink_set_status_works = 1; // assume good things
+           // test that it actually worked using ioctl.
+           s = socket(AF_INET, SOCK_DGRAM, 0);
+           memset(&ifreq, 0, sizeof(ifreq));
+           strncpy(ifreq.ifr_name, ifname.c_str(), sizeof(ifreq.ifr_name) - 1);
+           ifreq.ifr_flags = interface_flags;
+           if (ioctl(s, SIOCGIFFLAGS, &ifreq) < 0) {
+               error_msg = c_format("Cannot get the interface flags on "
+                                    "interface %s: %s",
+                                    ifname.c_str(),
+                                    strerror(errno));
+           }
+           else {
+               // Make sure we could at least set the enable/disable
+               if ((!!is_enabled) != (!!(ifreq.ifr_flags & IFF_UP))) {
+                   error_msg = c_format("ERROR:  Settting interface status 
using netlink failed"
+                                        " on: %s.  Will try to use ioctl 
method instead.",
+                                        ifname.c_str());
+                   XLOG_ERROR("%s", error_msg.c_str());
+                   // Seems it really is broken, don't try netlink again..just 
use ioctl.
+                   netlink_set_status_works = 0;
+                   goto use_ioctl;
+               }
+           }
+       }
     }
+    else {
+       //
+       // XXX: a work-around in case the kernel doesn't support setting
+       // the flags on an interface by using netlink.
+       // In this case, the work-around is to use ioctl(). Sigh...
+       //
+      use_ioctl:
+       if (s < 0) {
+           s = socket(AF_INET, SOCK_DGRAM, 0);
+       }
 
-    memset(&ifreq, 0, sizeof(ifreq));
-    strncpy(ifreq.ifr_name, ifname.c_str(), sizeof(ifreq.ifr_name) - 1);
-    ifreq.ifr_flags = interface_flags;
-    if (ioctl(s, SIOCSIFFLAGS, &ifreq) < 0) {
-       error_msg = c_format("Cannot set the interface flags to 0x%x on "
-                            "interface %s: %s",
-                            interface_flags,
-                            ifname.c_str(),
-                            strerror(errno));
+       if (s < 0) {
+           XLOG_ERROR("Could not initialize IPv4 ioctl() socket while trying 
to set status: %s",
+                      strerror(errno));
+           return XORP_ERROR;
+       }
+       
+       memset(&ifreq, 0, sizeof(ifreq));
+
+       strncpy(ifreq.ifr_name, ifname.c_str(), sizeof(ifreq.ifr_name) - 1);
+       ifreq.ifr_flags = interface_flags;
+       if (ioctl(s, SIOCSIFFLAGS, &ifreq) < 0) {
+           error_msg = c_format("Cannot set the interface flags to 0x%x on "
+                                "interface %s: %s",
+                                interface_flags,
+                                ifname.c_str(),
+                                strerror(errno));
+           close(s);
+           return (XORP_ERROR);
+       }
        close(s);
-       return (XORP_ERROR);
     }
-    close(s);
-
     return (XORP_OK);
-
-#endif // HAVE_NETLINK_SOCKETS_SET_FLAGS_IS_BROKEN
 }
 
 void
_______________________________________________
Xorp-hackers mailing list
[email protected]
http://mailman.ICSI.Berkeley.EDU/mailman/listinfo/xorp-hackers

Reply via email to