Hi Felix,

Regarding the resubmitted netifd linksensing patches (which solve the
original issue reported in
https://dev.openwrt.org/ticket/14590) did you have some time to review them
?
I noticed two other netifd patches were applied from the same patch series
but none of the linksensing and bridge mtu patches.

Thx,
Hans

On Tue, Feb 11, 2014 at 10:30 AM, Hans Dedecker <dedec...@gmail.com> wrote:

> Device layer is informed by netlink events regarding the link layer
> status. Link
> layer status change results in a DEV_EVENT_LINK_UP/DEV_EVENT_LINK_DOWN
> broadcast
> event for a given device.
>
> Depends on uloop error callback patch.
>
> Solves issue reported in https://dev.openwrt.org/ticket/14590
>
> Signed-off-by: Hans Dedecker <dedec...@gmail.com>
> Acked-by: Karl Vogel <karl.vo...@gmail.com>
> ---
>  device.c       |   29 ++++++++++-
>  device.h       |    4 ++
>  system-linux.c |  154
> +++++++++++++++++++++++++++++++++++++++++++++++--------
>  3 files changed, 162 insertions(+), 25 deletions(-)
>
> diff --git a/device.c b/device.c
> index feeb290..6a770ac 100644
> --- a/device.c
> +++ b/device.c
> @@ -211,7 +211,7 @@ int device_claim(struct device_user *dep)
>                 return 0;
>
>         dep->claimed = true;
> -       D(DEVICE, "Claim %s %s, new refcount: %d\n", dev->type->name,
> dev->ifname, dev->active + 1);
> +       D(DEVICE, "Claim %s %s, new active count: %d\n", dev->type->name,
> dev->ifname, dev->active + 1);
>         if (++dev->active != 1)
>                 return 0;
>
> @@ -237,7 +237,7 @@ void device_release(struct device_user *dep)
>
>         dep->claimed = false;
>         dev->active--;
> -       D(DEVICE, "Release %s %s, new refcount: %d\n", dev->type->name,
> dev->ifname, dev->active);
> +       D(DEVICE, "Release %s %s, new active count: %d\n",
> dev->type->name, dev->ifname, dev->active);
>         assert(dev->active >= 0);
>
>         if (dev->active)
> @@ -394,6 +394,26 @@ void device_set_present(struct device *dev, bool
> state)
>         device_refresh_present(dev);
>  }
>
> +void device_set_link(struct device *dev, bool state)
> +{
> +       if (dev->link_active == state)
> +               return;
> +
> +       netifd_log_message(L_NOTICE, "%s '%s' link is %s\n",
> dev->type->name, dev->ifname, state ? "up" : "down" );
> +
> +       dev->link_active = state;
> +       device_broadcast_event(dev, state ? DEV_EVENT_LINK_UP :
> DEV_EVENT_LINK_DOWN);
> +}
> +
> +void device_set_ifindex(struct device *dev, int ifindex)
> +{
> +       if (dev->ifindex == ifindex)
> +               return;
> +
> +       dev->ifindex = ifindex;
> +       device_broadcast_event(dev, DEV_EVENT_UPDATE_IFINDEX);
> +}
> +
>  static int device_refcount(struct device *dev)
>  {
>         struct list_head *list;
> @@ -435,6 +455,9 @@ void device_add_user(struct device_user *dep, struct
> device *dev)
>                 dep->cb(dep, DEV_EVENT_ADD);
>                 if (dev->active)
>                         dep->cb(dep, DEV_EVENT_UP);
> +
> +               if (dev->link_active)
> +                       dep->cb(dep, DEV_EVENT_LINK_UP);
>         }
>  }
>
> @@ -667,6 +690,8 @@ device_dump_status(struct blob_buf *b, struct device
> *dev)
>                 return;
>
>         blobmsg_add_u8(b, "up", !!dev->active);
> +       blobmsg_add_u8(b, "carrier", !!dev->link_active);
> +
>         if (dev->type->dump_info)
>                 dev->type->dump_info(dev, b);
>         else
> diff --git a/device.h b/device.h
> index d63ffe3..dd57927 100644
> --- a/device.h
> +++ b/device.h
> @@ -68,6 +68,7 @@ enum device_event {
>         DEV_EVENT_REMOVE,
>
>         DEV_EVENT_UPDATE_IFNAME,
> +       DEV_EVENT_UPDATE_IFINDEX,
>
>         DEV_EVENT_SETUP,
>         DEV_EVENT_TEARDOWN,
> @@ -122,6 +123,7 @@ struct device {
>         bool sys_present;
>         bool present;
>         int active;
> +       bool link_active;
>
>         bool external;
>         bool disabled;
> @@ -178,6 +180,8 @@ void device_remove_user(struct device_user *dep);
>  void device_broadcast_event(struct device *dev, enum device_event ev);
>
>  void device_set_present(struct device *dev, bool state);
> +void device_set_link(struct device *dev, bool state);
> +void device_set_ifindex(struct device *dev, int ifindex);
>  void device_refresh_present(struct device *dev);
>  int device_claim(struct device_user *dep);
>  void device_release(struct device_user *dep);
> diff --git a/system-linux.c b/system-linux.c
> index e1b9924..f0cea34 100644
> --- a/system-linux.c
> +++ b/system-linux.c
> @@ -58,7 +58,7 @@
>  struct event_socket {
>         struct uloop_fd uloop;
>         struct nl_sock *sock;
> -       struct nl_cb *cb;
> +       int bufsize;
>  };
>
>  static int sock_ioctl = -1;
> @@ -73,7 +73,38 @@ static void
>  handler_nl_event(struct uloop_fd *u, unsigned int events)
>  {
>         struct event_socket *ev = container_of(u, struct event_socket,
> uloop);
> -       nl_recvmsgs(ev->sock, ev->cb);
> +       int err;
> +       socklen_t errlen = sizeof(err);
> +
> +       if (!u->error) {
> +               nl_recvmsgs_default(ev->sock);
> +               return;
> +       }
> +
> +       if (getsockopt(u->fd, SOL_SOCKET, SO_ERROR, (void *)&err, &errlen))
> +               goto abort;
> +
> +       switch(err) {
> +       case ENOBUFS:
> +               // Increase rx buffer size on netlink socket
> +               ev->bufsize *= 2;
> +               if (nl_socket_set_buffer_size(ev->sock, ev->bufsize, 0))
> +                       goto abort;
> +
> +               // Request full dump since some info got dropped
> +               struct rtgenmsg msg = { .rtgen_family = AF_UNSPEC };
> +               nl_send_simple(ev->sock, RTM_GETLINK, NLM_F_DUMP, &msg,
> sizeof(msg));
> +               break;
> +
> +       default:
> +               goto abort;
> +       }
> +       u->error = false;
> +       return;
> +
> +abort:
> +       uloop_fd_delete(&ev->uloop);
> +       return;
>  }
>
>  static struct nl_sock *
> @@ -96,7 +127,7 @@ create_socket(int protocol, int groups)
>
>  static bool
>  create_raw_event_socket(struct event_socket *ev, int protocol, int groups,
> -                       uloop_fd_handler cb)
> +                        uloop_fd_handler cb, int flags)
>  {
>         ev->sock = create_socket(protocol, groups);
>         if (!ev->sock)
> @@ -104,7 +135,9 @@ create_raw_event_socket(struct event_socket *ev, int
> protocol, int groups,
>
>         ev->uloop.fd = nl_socket_get_fd(ev->sock);
>         ev->uloop.cb = cb;
> -       uloop_fd_add(&ev->uloop, ULOOP_READ | ULOOP_EDGE_TRIGGER);
> +       if (uloop_fd_add(&ev->uloop, ULOOP_READ|flags))
> +               return false;
> +
>         return true;
>  }
>
> @@ -112,14 +145,21 @@ static bool
>  create_event_socket(struct event_socket *ev, int protocol,
>                     int (*cb)(struct nl_msg *msg, void *arg))
>  {
> -       // Prepare socket for link events
> -       ev->cb = nl_cb_alloc(NL_CB_DEFAULT);
> -       if (!ev->cb)
> +       if (!create_raw_event_socket(ev, protocol, 0, handler_nl_event,
> ULOOP_ERROR_CB))
>                 return false;
>
> -       nl_cb_set(ev->cb, NL_CB_VALID, NL_CB_CUSTOM, cb, NULL);
> +       // Install the valid custom callback handler
> +       nl_socket_modify_cb(ev->sock, NL_CB_VALID, NL_CB_CUSTOM, cb, NULL);
> +
> +       // Disable sequence number checking on event sockets
> +       nl_socket_disable_seq_check(ev->sock);
>
> -       return create_raw_event_socket(ev, protocol, 0, handler_nl_event);
> +       // Increase rx buffer size to 65K on event sockets
> +       ev->bufsize = 65535;
> +       if (nl_socket_set_buffer_size(ev->sock, ev->bufsize, 0))
> +               return false;
> +
> +       return true;
>  }
>
>  int system_init(void)
> @@ -128,7 +168,7 @@ int system_init(void)
>         static struct event_socket hotplug_event;
>
>         sock_ioctl = socket(AF_LOCAL, SOCK_DGRAM, 0);
> -       fcntl(sock_ioctl, F_SETFD, fcntl(sock_ioctl, F_GETFD) |
> FD_CLOEXEC);
> +       system_fd_set_cloexec(sock_ioctl);
>
>         // Prepare socket for routing / address control
>         sock_rtnl = create_socket(NETLINK_ROUTE, 0);
> @@ -139,7 +179,7 @@ int system_init(void)
>                 return -1;
>
>         if (!create_raw_event_socket(&hotplug_event,
> NETLINK_KOBJECT_UEVENT, 1,
> -                                    handle_hotplug_event))
> +                                    handle_hotplug_event, 0))
>                 return -1;
>
>         // Receive network link events form kernel
> @@ -171,6 +211,10 @@ static void system_set_disable_ipv6(struct device
> *dev, const char *val)
>         system_set_dev_sysctl("/proc/sys/net/ipv6/conf/%s/disable_ipv6",
> dev->ifname, val);
>  }
>
> +#ifndef IFF_LOWER_UP
> +#define IFF_LOWER_UP   0x10000
> +#endif
> +
>  // Evaluate netlink messages
>  static int cb_rtnl_event(struct nl_msg *msg, void *arg)
>  {
> @@ -178,19 +222,19 @@ static int cb_rtnl_event(struct nl_msg *msg, void
> *arg)
>         struct ifinfomsg *ifi = NLMSG_DATA(nh);
>         struct nlattr *nla[__IFLA_MAX];
>
> -       if (nh->nlmsg_type != RTM_DELLINK && nh->nlmsg_type != RTM_NEWLINK)
> +       if (nh->nlmsg_type != RTM_NEWLINK)
>                 goto out;
>
>         nlmsg_parse(nh, sizeof(*ifi), nla, __IFLA_MAX - 1, NULL);
>         if (!nla[IFLA_IFNAME])
>                 goto out;
>
> -       struct device *dev = device_get(RTA_DATA(nla[IFLA_IFNAME]), false);
> +       struct device *dev = device_get(nla_data(nla[IFLA_IFNAME]), false);
>         if (!dev)
>                 goto out;
>
> -       dev->ifindex = ifi->ifi_index;
> -       /* TODO: parse link status */
> +       device_set_ifindex(dev, ifi->ifi_index);
> +       device_set_link(dev, ifi->ifi_flags & IFF_LOWER_UP ? true : false);
>
>  out:
>         return 0;
> @@ -538,7 +582,7 @@ void system_if_clear_state(struct device *dev)
>         if (dev->external)
>                 return;
>
> -       dev->ifindex = system_if_resolve(dev);
> +       device_set_ifindex(dev, system_if_resolve(dev));
>         if (!dev->ifindex)
>                 return;
>
> @@ -782,7 +826,7 @@ int system_if_up(struct device *dev)
>  {
>         system_if_get_settings(dev, &dev->orig_settings);
>         system_if_apply_settings(dev, &dev->settings);
> -       dev->ifindex = system_if_resolve(dev);
> +       device_set_ifindex(dev, system_if_resolve(dev));
>         return system_if_flags(dev->ifname, IFF_UP, 0);
>  }
>
> @@ -794,10 +838,78 @@ int system_if_down(struct device *dev)
>         return ret;
>  }
>
> +struct if_check_data {
> +       struct device *dev;
> +       int pending;
> +       int ret;
> +};
> +
> +static int cb_if_check_valid(struct nl_msg *msg, void *arg)
> +{
> +       struct nlmsghdr *nh = nlmsg_hdr(msg);
> +       struct ifinfomsg *ifi = NLMSG_DATA(nh);
> +       struct if_check_data *chk = (struct if_check_data *)arg;
> +
> +       if (nh->nlmsg_type != RTM_NEWLINK)
> +               return NL_SKIP;
> +
> +       device_set_present(chk->dev, ifi->ifi_index > 0 ? true : false);
> +       device_set_link(chk->dev, ifi->ifi_flags & IFF_LOWER_UP ? true :
> false);
> +
> +       return NL_OK;
> +}
> +
> +static int cb_if_check_ack(struct nl_msg *msg, void *arg)
> +{
> +       struct if_check_data *chk = (struct if_check_data *)arg;
> +       chk->pending = 0;
> +       return NL_STOP;
> +}
> +
> +static int cb_if_check_error(struct sockaddr_nl *nla, struct nlmsgerr
> *err, void *arg)
> +{
> +       struct if_check_data *chk = (struct if_check_data *)arg;
> +
> +       device_set_present(chk->dev, false);
> +       device_set_link(chk->dev, false);
> +       chk->pending = err->error;
> +
> +       return NL_STOP;
> +}
> +
>  int system_if_check(struct device *dev)
>  {
> -       device_set_present(dev, (system_if_resolve(dev) > 0));
> -       return 0;
> +       struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT);
> +       struct nl_msg *msg;
> +       struct ifinfomsg ifi = {
> +               .ifi_family = AF_UNSPEC,
> +               .ifi_index = 0,
> +       };
> +       struct if_check_data chk = {
> +               .dev = dev,
> +               .pending = 1,
> +       };
> +       int ret = 1;
> +
> +       msg = nlmsg_alloc_simple(RTM_GETLINK, 0);
> +       if (!msg || nlmsg_append(msg, &ifi, sizeof(ifi), 0) ||
> +           nla_put_string(msg, IFLA_IFNAME, dev->ifname))
> +               goto out;
> +
> +       nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_if_check_valid, &chk);
> +       nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, cb_if_check_ack, &chk);
> +       nl_cb_err(cb, NL_CB_CUSTOM, cb_if_check_error, &chk);
> +
> +       nl_send_auto_complete(sock_rtnl, msg);
> +       while (chk.pending > 0)
> +               nl_recvmsgs(sock_rtnl, cb);
> +
> +       nlmsg_free(msg);
> +       ret = chk.pending;
> +
> +out:
> +       nl_cb_put(cb);
> +       return ret;
>  }
>
>  struct device *
> @@ -915,14 +1027,10 @@ system_if_dump_info(struct device *dev, struct
> blob_buf *b)
>         char buf[64], *s;
>         void *c;
>         int dir_fd;
> -       uint64_t val = 0;
>
>         snprintf(buf, sizeof(buf), "/sys/class/net/%s", dev->ifname);
>         dir_fd = open(buf, O_DIRECTORY);
>
> -       if (read_uint64_file(dir_fd, "carrier", &val))
> -               blobmsg_add_u8(b, "link", !!val);
> -
>         memset(&ecmd, 0, sizeof(ecmd));
>         memset(&ifr, 0, sizeof(ifr));
>         strcpy(ifr.ifr_name, dev->ifname);
> --
> 1.7.1
>
>
_______________________________________________
openwrt-devel mailing list
openwrt-devel@lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel

Reply via email to