diff --git a/client/ifstatus.c b/client/ifstatus.c
index 3ad35e5b3..00af7c4cb 100644
--- a/client/ifstatus.c
+++ b/client/ifstatus.c
@@ -329,18 +329,17 @@ ni_ifstatus_show_addrs(const ni_netdev_t *dev, ni_bool_t verbose)
ni_address_t *ap;
for (ap = dev->addrs; ap; ap = ap->next) {
- if (ni_address_is_duplicate(ap))
- continue;
- if (ni_address_is_deprecated(ap))
+ if (!ni_sockaddr_is_specified(&ap->local_addr))
continue;
if (ni_address_is_linklocal(ap) && !verbose)
continue;
- if (!ni_sockaddr_is_specified(&ap->local_addr))
- continue;
- if_printf("", "addr:", "%s %s/%u",
+ ni_address_format_flags(&buf, ap->family, ap->flags, "|");
+ if_printf("", "addr:", "%s %s/%u%s%s",
ni_addrfamily_type_to_name(ap->family),
- ni_sockaddr_print(&ap->local_addr), ap->prefixlen);
+ ni_sockaddr_print(&ap->local_addr), ap->prefixlen,
+ buf.string ? " " : "", buf.string ? buf.string : "");
+ ni_stringbuf_destroy(&buf);
if (verbose) {
if (ap->family == AF_INET) {
diff --git a/dhcp6/device.c b/dhcp6/device.c
index 74649034c..1540b6977 100644
--- a/dhcp6/device.c
+++ b/dhcp6/device.c
@@ -1125,6 +1125,13 @@ ni_dhcp6_device_event(ni_dhcp6_device_t *dev, ni_netdev_t *ifp, ni_event_t event
}
break;
+ case NI_EVENT_DEVICE_CHANGE:
+ if (dev->config && dev->config->mode == NI_DHCP6_MODE_AUTO) {
+ ni_dhcp6_device_update_mode(dev, ifp);
+ ni_dhcp6_device_start(dev);
+ }
+ break;
+
default:
ni_debug_dhcp("%s: received other event", dev->ifname);
break;
@@ -1170,22 +1177,7 @@ void
ni_dhcp6_prefix_event(ni_dhcp6_device_t *dev, ni_netdev_t *ifp, ni_event_t event,
const ni_ipv6_ra_pinfo_t *pi)
{
- ni_ipv6_devinfo_t *ipv6;
-
- ipv6 = ni_netdev_get_ipv6(ifp);
- if (ipv6 == NULL)
- return;
-
- ni_debug_verbose(NI_LOG_DEBUG2, NI_TRACE_EVENTS,
- "%s: %s RA<%s> Prefix<%s/%u %s,%s> [%d,%d]", dev->ifname,
- (event == NI_EVENT_PREFIX_UPDATE ? "update" : "delete"),
- (ipv6->radv.managed_addr ? "managed-address" :
- (ipv6->radv.other_config ? "managed-config" : "unmanaged")),
- ni_sockaddr_print(&pi->prefix), pi->length,
- (pi->on_link ? "onlink" : "not-onlink"),
- (pi->autoconf ? "autoconf" : "no-autoconf"),
- pi->lifetime.preferred_lft, pi->lifetime.valid_lft);
-
+ ni_server_trace_interface_prefix_events(ifp, event, pi);
switch (event) {
case NI_EVENT_PREFIX_UPDATE:
if (dev->config && dev->config->mode == NI_DHCP6_MODE_AUTO) {
diff --git a/dhcp6/main.c b/dhcp6/main.c
index dd11e9b45..0c04763c2 100644
--- a/dhcp6/main.c
+++ b/dhcp6/main.c
@@ -547,6 +547,7 @@ dhcp6_interface_event(ni_netdev_t *ifp, ni_event_t event)
dhcp6_device_destroy(dhcp6_dbus_server, ifp);
break;
+ case NI_EVENT_DEVICE_CHANGE:
case NI_EVENT_DEVICE_DOWN:
case NI_EVENT_DEVICE_UP:
case NI_EVENT_NETWORK_DOWN:
diff --git a/include/wicked/address.h b/include/wicked/address.h
index 7a6880c8b..b9e2ec9ff 100644
--- a/include/wicked/address.h
+++ b/include/wicked/address.h
@@ -93,11 +93,12 @@ extern unsigned int ni_af_address_prefixlen(int af);
extern ni_address_t * ni_address_new(int af, unsigned int prefix_len,
const ni_sockaddr_t *local_addr,
ni_address_t **list);
+extern void ni_address_free(ni_address_t *);
+extern const char * ni_address_format_flags(ni_stringbuf_t *, unsigned int, unsigned int, const char *);
extern void ni_address_list_append(ni_address_t **, ni_address_t *);
extern void ni_address_list_destroy(ni_address_t **);
extern void ni_address_list_dedup(ni_address_t **);
extern ni_address_t * ni_address_list_find(ni_address_t *, const ni_sockaddr_t *);
extern unsigned int ni_address_list_count(ni_address_t *list);
-extern void ni_address_free(ni_address_t *);
#endif /* __WICKED_ADDRESS_H__ */
diff --git a/include/wicked/netinfo.h b/include/wicked/netinfo.h
index 6a505495d..701ece9e6 100644
--- a/include/wicked/netinfo.h
+++ b/include/wicked/netinfo.h
@@ -119,6 +119,9 @@ extern int ni_server_enable_interface_addr_events(void (*handler)(ni_netdev_t *
extern int ni_server_enable_interface_prefix_events(void (*handler)(ni_netdev_t *, ni_event_t, const ni_ipv6_ra_pinfo_t *));
extern int ni_server_enable_interface_nduseropt_events(void (*handler)(ni_netdev_t *, ni_event_t));
extern int ni_server_enable_interface_uevents(void);
+extern void ni_server_trace_interface_addr_events(ni_netdev_t *, ni_event_t, const ni_address_t *);
+extern void ni_server_trace_interface_prefix_events(ni_netdev_t *, ni_event_t, const ni_ipv6_ra_pinfo_t *);
+extern void ni_server_trace_interface_nduseropt_events(ni_netdev_t *, ni_event_t);
extern void ni_server_deactivate_interface_events(void);
extern void ni_server_deactivate_interface_uevents(void);
extern ni_bool_t ni_server_listens_uevents(void);
diff --git a/schema/interface.xml b/schema/interface.xml
index ebd2aff30..ab26e2183 100644
--- a/schema/interface.xml
+++ b/schema/interface.xml
@@ -9,6 +9,10 @@
+
+
+
+
diff --git a/server/main.c b/server/main.c
index cf6a58bd2..5f5fb6a89 100644
--- a/server/main.c
+++ b/server/main.c
@@ -85,6 +85,9 @@ static void run_interface_server(void);
static void discover_state(ni_dbus_server_t *);
static void recover_state(const char *filename);
static void handle_interface_event(ni_netdev_t *, ni_event_t);
+static void handle_interface_addr_events(ni_netdev_t *, ni_event_t, const ni_address_t *);
+static void handle_interface_prefix_events(ni_netdev_t *, ni_event_t, const ni_ipv6_ra_pinfo_t *);
+static void handle_interface_nduseropt_events(ni_netdev_t *, ni_event_t);
static void handle_rfkill_event(ni_rfkill_type_t, ni_bool_t, void *);
static void handle_other_event(ni_event_t);
#ifdef MODEM
@@ -240,6 +243,12 @@ run_interface_server(void)
/* open global RTNL socket to listen for kernel events */
if (ni_server_listen_interface_events(handle_interface_event) < 0)
ni_fatal("unable to initialize netlink listener");
+ if (ni_server_enable_interface_addr_events(handle_interface_addr_events) < 0)
+ ni_fatal("unable to initialize netlink address listener");
+ if (ni_server_enable_interface_prefix_events(handle_interface_prefix_events) < 0)
+ ni_fatal("unable to initialize netlink prefix listener");
+ if (ni_server_enable_interface_nduseropt_events(handle_interface_nduseropt_events) < 0)
+ ni_fatal("unable to initialize netlink nduseropt listener");
if (ni_udev_net_subsystem_available()) {
if (ni_server_enable_interface_uevents() < 0)
@@ -421,6 +430,24 @@ handle_interface_event(ni_netdev_t *dev, ni_event_t event)
}
}
+static void
+handle_interface_addr_events(ni_netdev_t *dev, ni_event_t event, const ni_address_t *ap)
+{
+ ni_server_trace_interface_addr_events(dev, event, ap);
+}
+
+static void
+handle_interface_prefix_events(ni_netdev_t *dev, ni_event_t event, const ni_ipv6_ra_pinfo_t *pi)
+{
+ ni_server_trace_interface_prefix_events(dev, event, pi);
+}
+
+static void
+handle_interface_nduseropt_events(ni_netdev_t *dev, ni_event_t event)
+{
+ ni_server_trace_interface_nduseropt_events(dev, event);
+}
+
static void
handle_other_event(ni_event_t event)
{
diff --git a/src/address.c b/src/address.c
index 72c16bf46..e17d415f3 100644
--- a/src/address.c
+++ b/src/address.c
@@ -24,6 +24,13 @@
#include
#include "util_priv.h"
+#ifndef IFA_F_MANAGETEMPADDR
+#define IFA_F_MANAGETEMPADDR 0x100
+#endif
+#ifndef IFA_F_NOPREFIXROUTE
+#define IFA_F_NOPREFIXROUTE 0x200
+#endif
+
#ifndef offsetof
# define offsetof(type, member) \
((unsigned long) &(((type *) NULL)->member))
@@ -68,6 +75,55 @@ ni_address_free(ni_address_t *ap)
free(ap);
}
+static const ni_intmap_t __ni_address_ipv4_flag_map[] = {
+ { "secondary", IFA_F_SECONDARY },
+ { "permanent", IFA_F_PERMANENT },
+ { "deprecated", IFA_F_DEPRECATED },
+ { NULL, 0 }
+};
+
+static const ni_intmap_t __ni_address_ipv6_flag_map[] = {
+ { "temporary", IFA_F_TEMPORARY },
+ { "nodad", IFA_F_NODAD },
+ { "optimistic", IFA_F_OPTIMISTIC },
+ { "duplicate", IFA_F_DADFAILED },
+ { "homeaddress", IFA_F_HOMEADDRESS },
+ { "deprecated", IFA_F_DEPRECATED },
+ { "tentative", IFA_F_TENTATIVE },
+ { "permanent", IFA_F_PERMANENT },
+ { "mngtmpaddr", IFA_F_MANAGETEMPADDR },
+ { "noprefixroute", IFA_F_NOPREFIXROUTE },
+ { NULL, 0 }
+};
+
+const char *
+ni_address_format_flags(ni_stringbuf_t *buf, unsigned int family,
+ unsigned int flags, const char *sep)
+{
+ const ni_intmap_t *map;
+ unsigned int i;
+
+ if (!buf)
+ return NULL;
+ switch (family) {
+ case AF_INET: map = __ni_address_ipv4_flag_map; break;
+ case AF_INET6: map = __ni_address_ipv6_flag_map; break;
+ default: return NULL;
+ }
+
+ if (ni_string_empty(sep))
+ sep = "|";
+
+ for (i = 0; map->name; ++map) {
+ if (flags & map->value) {
+ if (i++)
+ ni_stringbuf_puts(buf, sep);
+ ni_stringbuf_puts(buf, map->name);
+ }
+ }
+ return buf->string;
+}
+
ni_bool_t
ni_address_is_loopback(const ni_address_t *laddr)
{
diff --git a/src/dbus-objects/misc.c b/src/dbus-objects/misc.c
index 870524608..7950b04c1 100644
--- a/src/dbus-objects/misc.c
+++ b/src/dbus-objects/misc.c
@@ -569,6 +569,10 @@ __ni_objectmodel_address_to_dict(const ni_address_t *ap, ni_dbus_variant_t *dict
__ni_objectmodel_dict_add_sockaddr(dict, "anycast", &ap->anycast_addr);
if (ap->bcast_addr.ss_family == ap->family)
__ni_objectmodel_dict_add_sockaddr(dict, "broadcast", &ap->bcast_addr);
+
+ if (ap->flags)
+ ni_dbus_dict_add_uint32(dict, "flags", ap->flags);
+
if (ap->family == AF_INET && ap->label)
ni_dbus_dict_add_string(dict, "label", ap->label);
@@ -607,6 +611,11 @@ __ni_objectmodel_address_from_dict(ni_address_t **list, const ni_dbus_variant_t
__ni_objectmodel_dict_get_sockaddr(dict, "anycast", &ap->anycast_addr);
__ni_objectmodel_dict_get_sockaddr(dict, "broadcast", &ap->bcast_addr);
+ /* Do we need to translate them and map to names?
+ * The usable flags differ between address families and
+ * ipv6 temporary flag is same bit as secondary in ipv4.
+ */
+ ni_dbus_dict_get_uint32(dict, "flags", &ap->flags);
if (ap->family == AF_INET) {
if (ni_dbus_dict_get_string(dict, "label", &label))
ni_string_dup(&ap->label, label);
diff --git a/src/ifevent.c b/src/ifevent.c
index 11b2bac80..ec7ed79cf 100644
--- a/src/ifevent.c
+++ b/src/ifevent.c
@@ -370,16 +370,6 @@ __ni_rtevent_newprefix(ni_netconfig_t *nc, const struct sockaddr_nl *nladdr, str
free(pi);
return -1;
}
-#if 0
- ni_debug_verbose(NI_LOG_DEBUG3, NI_TRACE_EVENTS,
- "%s: RA<%s>, Prefix<%s/%u %s,%s>[%u, %u]", dev->name,
- (ipv6->radv.managed_addr ? "managed-address" :
- (ipv6->radv.other_config ? "other-config" : "unmanaged")),
- ni_sockaddr_print(&pi->prefix), pi->length,
- (pi->on_link ? "onlink" : "not-onlink"),
- (pi->autoconf ? "autoconf" : "no-autoconf"),
- pi->lifetime.preferred_lft, pi->lifetime.valid_lft);
-#endif
if ((old = ni_ipv6_ra_pinfo_list_remove(&ipv6->radv.pinfo, pi)) != NULL) {
if (pi->lifetime.valid_lft > 0) {
@@ -486,26 +476,12 @@ __ni_rtevent_process_rdnss_info(ni_netdev_t *dev, const struct nd_opt_hdr *opt,
ni_ipv6_ra_rdnss_reset(ipv6->radv.rdnss);
ipv6->radv.rdnss->lifetime = ntohl(rdnss->nd_opt_rdnss_lifetime);
- if (ipv6->radv.rdnss->lifetime == 0xffffffff)
- ni_debug_events("%s: rdnss lifetime: infinite", dev->name);
- else
- ni_debug_events("%s: rdnss lifetime: %u", dev->name,
- ipv6->radv.rdnss->lifetime);
-
len -= sizeof(*rdnss);
addr = &rdnss->nd_opt_rdnss_addr[0];
for ( ; len >= sizeof(*addr); len -= sizeof(*addr), ++addr) {
if (IN6_IS_ADDR_LOOPBACK(addr) || IN6_IS_ADDR_UNSPECIFIED(addr))
continue;
-
ni_ipv6_ra_rdnss_add_server(ipv6->radv.rdnss, addr);
-
- if (ni_log_facility(NI_TRACE_EVENTS)) {
- const ni_sockaddr_array_t *addrs = &ipv6->radv.rdnss->addrs;
-
- ni_debug_events("%s: rdnss address: %s", dev->name,
- ni_sockaddr_print(&addrs->data[addrs->count-1]));
- }
}
__ni_netdev_nduseropt_event(dev, NI_EVENT_RDNSS_UPDATE);
return 0;
@@ -544,7 +520,8 @@ __ni_rtevent_process_nd_radv_opts(ni_netdev_t *dev, const struct nd_opt_hdr *opt
default:
/* kernels up to at least 3.4 do not provide other */
- ni_debug_events("%s: unhandled nd user option %d",
+ ni_debug_verbose(NI_LOG_DEBUG1, NI_TRACE_IPV6|NI_TRACE_EVENTS,
+ "%s: unhandled nd user option %d",
dev->name, opt->nd_opt_type);
break;
}
@@ -747,6 +724,20 @@ ni_server_listen_interface_events(void (*ifevent_handler)(ni_netdev_t *, ni_even
return 0;
}
+void
+ni_server_trace_interface_addr_events(ni_netdev_t *dev, ni_event_t event, const ni_address_t *ap)
+{
+ ni_stringbuf_t flags = NI_STRINGBUF_INIT_DYNAMIC;
+
+ ni_address_format_flags(&flags, ap->family, ap->flags, NULL);
+ ni_debug_verbose(NI_LOG_DEBUG2, NI_TRACE_IPV6|NI_TRACE_EVENTS,
+ "%s: %s event: %s flags[%u] %s",
+ dev->name, ni_event_type_to_name(event),
+ ni_sockaddr_prefix_print(&ap->local_addr, ap->prefixlen),
+ ap->flags, flags.string ? flags.string : "");
+ ni_stringbuf_destroy(&flags);
+}
+
int
ni_server_enable_interface_addr_events(void (*ifaddr_handler)(ni_netdev_t *, ni_event_t, const ni_address_t *))
{
@@ -769,6 +760,20 @@ ni_server_enable_interface_addr_events(void (*ifaddr_handler)(ni_netdev_t *, ni_
return 0;
}
+void
+ni_server_trace_interface_prefix_events(ni_netdev_t *dev, ni_event_t event, const ni_ipv6_ra_pinfo_t *pi)
+{
+ ni_debug_verbose(NI_LOG_DEBUG2, NI_TRACE_IPV6|NI_TRACE_EVENTS,
+ "%s: %s IPv6 RA<%s> Prefix<%s/%u %s,%s>[%u, %u]", dev->name,
+ (event == NI_EVENT_PREFIX_UPDATE ? "update" : "delete"),
+ (dev->ipv6 && dev->ipv6->radv.managed_addr ? "managed" :
+ (dev->ipv6 && dev->ipv6->radv.other_config ? "config" : "unmanaged")),
+ ni_sockaddr_print(&pi->prefix), pi->length,
+ (pi->on_link ? "onlink" : "not-onlink"),
+ (pi->autoconf ? "autoconf" : "no-autoconf"),
+ pi->lifetime.preferred_lft, pi->lifetime.valid_lft);
+}
+
int
ni_server_enable_interface_prefix_events(void (*ifprefix_handler)(ni_netdev_t *, ni_event_t, const ni_ipv6_ra_pinfo_t *))
{
@@ -784,6 +789,42 @@ ni_server_enable_interface_prefix_events(void (*ifprefix_handler)(ni_netdev_t *,
return 0;
}
+void
+ni_server_trace_interface_nduseropt_events(ni_netdev_t *dev, ni_event_t event)
+{
+ ni_ipv6_devinfo_t *ipv6 = dev->ipv6;
+
+ if (!ni_debug_guard(NI_LOG_DEBUG2, NI_TRACE_IPV6|NI_TRACE_EVENTS))
+ return;
+
+ switch (event) {
+ case NI_EVENT_RDNSS_UPDATE:
+ if (ipv6 && ipv6->radv.rdnss && ipv6->radv.rdnss->addrs.count) {
+ char lifetime[32] = "infinite";
+ const char *rainfo;
+ unsigned int i;
+
+ rainfo = ipv6->radv.managed_addr ? "managed" :
+ ipv6->radv.other_config ? "config" : "unmanaged";
+ if (ipv6->radv.rdnss->lifetime != 0xffffffff) {
+ snprintf(lifetime, sizeof(lifetime), "%u",
+ ipv6->radv.rdnss->lifetime);
+ }
+ for (i = 0; i < ipv6->radv.rdnss->addrs.count; ++i) {
+ ni_trace("%s: update IPv6 RA<%s> RDNSS<%s>[%s]",
+ dev->name, rainfo,
+ ni_sockaddr_print(&ipv6->radv.rdnss->addrs.data[i]),
+ lifetime);
+ }
+ }
+ break;
+ default:
+ ni_debug_verbose(NI_LOG_DEBUG2, NI_TRACE_IPV6|NI_TRACE_EVENTS,
+ "%s: IPv6 RA %s event: ", dev->name, ni_event_type_to_name(event));
+ break;
+ }
+}
+
int
ni_server_enable_interface_nduseropt_events(void (*ifnduseropt_handler)(ni_netdev_t *, ni_event_t))
{