Can you try the attached patch and see if it works better?

This compile tested only.

I'd also like to see the error logs from the run with this patch if that's 
convenient.

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..b7d1800 100644
--- a/fea/data_plane/ifconfig/ifconfig_set_netlink_socket.cc
+++ b/fea/data_plane/ifconfig/ifconfig_set_netlink_socket.cc
@@ -540,101 +540,158 @@ 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;
+    bool test_ioctl = false;
+
+    // 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());
+           test_ioctl = true;
+           goto use_ioctl; // try ioctl method.
+       }
 
-    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) {
+           // 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("WARNING:  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.
+                   test_ioctl = true;
+                   goto use_ioctl;
+               }
+               else {
+                   netlink_set_status_works = 1; // looks like it worked
+               }
+           }
+       }
     }
+    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);
+       }
+       else {
+           // setting *seemed* to work, but let's check to make sure.
+           if (test_ioctl) {
+               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) {
+                   if ((!!is_enabled) == (!!(ifreq.ifr_flags & IFF_UP))) {
+                       // Ok, it all worked.  We assume that netlink just 
doesn't work, so
+                       // don't try it again.
+                       error_msg = c_format("WARNING:  Settting interface 
status using netlink failed"
+                                            " on: %s but ioctl method worked.  
Will use ioctl method from"
+                                            " now on.",
+                                            ifname.c_str());
+                       XLOG_ERROR("%s", error_msg.c_str());
+                       netlink_set_status_works = 0;
+                   }
+               }
+           }
+       }
        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