interface: add neighbor config support
authormeurisa <alexander.meuris@technicolor.com>
Fri, 12 Apr 2019 07:56:28 +0000 (09:56 +0200)
committerHans Dedecker <dedeckeh@gmail.com>
Mon, 15 Apr 2019 20:31:38 +0000 (22:31 +0200)
The neighbor or neighbor6 network section makes neighbours
configurable via UCI or proto shell handlers. It allows to
install neighbor proxy entries or static neighbor entries

The neighbor or neighbor6 section has the following types:
interface : declares the logical OpenWrt interface
ipaddr : the ip address of the neighbor
mac : the mac address of the neighbor
proxy : specifies whether the neighbor ia a proxy
entry (can be 1 or 0)
router : specifies whether the neighbor is a router
 (can be 1 or 0)

Signed-off-by: Alexander Meuris <meurisalexander@gmail.com>
Signed-off-by: Hans Dedecker <dedeckeh@gmail.com>
config.c
interface-ip.c
interface-ip.h
interface.h
proto-shell.c
scripts/netifd-proto.sh
system-dummy.c
system-linux.c
system.h
ubus.c

index be10379d55590f0fd124760fe4becaea56c4a9f1..843c53f622b896926519b77bb0331710ccee78b2 100644 (file)
--- a/config.c
+++ b/config.c
@@ -143,6 +143,17 @@ config_parse_route(struct uci_section *s, bool v6)
        interface_ip_add_route(NULL, blob_data(b.head), v6);
 }
 
+static void
+config_parse_neighbor(struct uci_section *s, bool v6)
+{
+       void *neighbor;
+       blob_buf_init(&b,0);
+       neighbor = blobmsg_open_array(&b, "neighbor");
+       uci_to_blob(&b,s, &neighbor_attr_list);
+       blobmsg_close_array(&b, neighbor);
+       interface_ip_add_neighbor(NULL, blob_data(b.head), v6);
+}
+
 static void
 config_parse_rule(struct uci_section *s, bool v6)
 {
@@ -251,7 +262,7 @@ config_init_interfaces(void)
 }
 
 static void
-config_init_routes(void)
+config_init_ip(void)
 {
        struct interface *iface;
        struct uci_element *e;
@@ -266,6 +277,10 @@ config_init_routes(void)
                        config_parse_route(s, false);
                else if (!strcmp(s->type, "route6"))
                        config_parse_route(s, true);
+               if (!strcmp(s->type, "neighbor"))
+                       config_parse_neighbor(s, false);
+               else if (!strcmp(s->type, "neighbor6"))
+                       config_parse_neighbor(s, true);
        }
 
        vlist_for_each_element(&interfaces, iface, node)
@@ -417,7 +432,7 @@ config_init_all(void)
        device_reset_config();
        config_init_devices();
        config_init_interfaces();
-       config_init_routes();
+       config_init_ip();
        config_init_rules();
        config_init_globals();
        config_init_wireless();
index 83f1dfa69c28d0d4f9775d26f9c18a8bb305d7e9..22c21d7a85ff41adfb6ccc2d39f72cd5b787978b 100644 (file)
 #include <arpa/inet.h>
 #include <netinet/in.h>
 
+#ifdef linux
+#include <netinet/ether.h>
+#endif
+
 #include "netifd.h"
 #include "device.h"
 #include "interface.h"
@@ -64,6 +68,28 @@ const struct uci_blob_param_list route_attr_list = {
        .params = route_attr,
 };
 
+enum {
+       NEIGHBOR_INTERFACE,
+       NEIGHBOR_ADDRESS,
+       NEIGHBOR_MAC,
+       NEIGHBOR_PROXY,
+       NEIGHBOR_ROUTER,
+       __NEIGHBOR_MAX
+};
+
+static const struct blobmsg_policy neighbor_attr[__NEIGHBOR_MAX]={
+       [NEIGHBOR_INTERFACE]= { .name = "interface", .type = BLOBMSG_TYPE_STRING},
+       [NEIGHBOR_ADDRESS]= { .name = "ipaddr", .type = BLOBMSG_TYPE_STRING},
+       [NEIGHBOR_MAC]= { .name = "mac", .type = BLOBMSG_TYPE_STRING},
+       [NEIGHBOR_PROXY]= { .name = "proxy", .type = BLOBMSG_TYPE_BOOL},
+       [NEIGHBOR_ROUTER]= {.name = "router", .type = BLOBMSG_TYPE_BOOL},
+};
+
+const struct uci_blob_param_list neighbor_attr_list = {
+       .n_params = __NEIGHBOR_MAX,
+       .params = neighbor_attr,
+};
+
 
 struct list_head prefixes = LIST_HEAD_INIT(prefixes);
 static struct device_prefix *ula_prefix = NULL;
@@ -298,6 +324,64 @@ interface_set_route_info(struct interface *iface, struct device_route *route)
        }
 }
 
+void
+interface_ip_add_neighbor(struct interface *iface, struct blob_attr *attr, bool v6)
+{
+       struct interface_ip_settings *ip;
+       struct blob_attr *tb[__NEIGHBOR_MAX], *cur;
+       struct device_neighbor *neighbor;
+       int af = v6 ? AF_INET6: AF_INET;
+       struct ether_addr *ea;
+
+       blobmsg_parse(neighbor_attr, __NEIGHBOR_MAX, tb, blobmsg_data(attr), blobmsg_data_len(attr));
+
+       if (!iface) {
+               if ((cur = tb[NEIGHBOR_INTERFACE]) == NULL)
+                       return;
+
+               iface = vlist_find(&interfaces, blobmsg_data(cur), iface, node);
+
+               if (!iface)
+                       return;
+
+               ip = &iface->config_ip;
+       } else
+               ip = &iface->proto_ip;
+
+       neighbor = calloc(1,sizeof(*neighbor));
+       neighbor->flags = v6 ? DEVADDR_INET6 : DEVADDR_INET4;
+
+       if (!neighbor)
+               return;
+
+       if ((cur = tb[NEIGHBOR_ADDRESS]) != NULL){
+               if (!inet_pton(af, blobmsg_data(cur), &neighbor->addr))
+                       goto error;
+       } else
+               goto error;
+
+       if ((cur = tb[NEIGHBOR_MAC]) != NULL) {
+               neighbor->flags |= DEVNEIGH_MAC;
+               ea = ether_aton(blobmsg_data(cur));
+               if (!ea)
+                       goto error;
+
+               memcpy(neighbor->macaddr, ea, 6);
+       }
+
+       if ((cur = tb[NEIGHBOR_PROXY]) != NULL)
+               neighbor->proxy = blobmsg_get_bool(cur);
+
+       if ((cur = tb[NEIGHBOR_ROUTER]) != NULL)
+               neighbor->router = blobmsg_get_bool(cur);
+
+       vlist_add(&ip->neighbor, &neighbor->node, neighbor);
+       return;
+
+error:
+       free(neighbor);
+}
+
 void
 interface_ip_add_route(struct interface *iface, struct blob_attr *attr, bool v6)
 {
@@ -428,6 +512,14 @@ addr_cmp(const void *k1, const void *k2, void *ptr)
                      offsetof(struct device_addr, flags));
 }
 
+static int
+neighbor_cmp(const void *k1, const void *k2, void *ptr)
+{
+       const struct device_neighbor *n1 = k1, *n2 = k2;
+
+       return memcmp(&n1->addr, &n2->addr, sizeof(n2->addr));
+}
+
 static int
 route_cmp(const void *k1, const void *k2, void *ptr)
 {
@@ -624,6 +716,44 @@ enable_route(struct interface_ip_settings *ip, struct device_route *route)
        return ip->enabled;
 }
 
+static void
+interface_update_proto_neighbor(struct vlist_tree *tree,
+                               struct vlist_node * node_new,
+                               struct vlist_node *node_old)
+{
+       struct device *dev;
+       struct device_neighbor *neighbor_old, *neighbor_new;
+       struct interface_ip_settings *ip;
+       bool keep = false;
+
+       ip = container_of(tree, struct interface_ip_settings, neighbor);
+       dev = ip->iface->l3_dev.dev;
+
+       neighbor_old = container_of(node_old, struct device_neighbor, node);
+       neighbor_new = container_of(node_new, struct device_neighbor, node);
+
+       if (node_old && node_new) {
+               keep = (!memcmp(neighbor_old->macaddr, neighbor_new->macaddr, sizeof(neighbor_old->macaddr)) &&
+                       (neighbor_old->proxy == neighbor_new->proxy) &&
+                       (neighbor_old->router == neighbor_new->router));
+       }
+
+       if (node_old) {
+               if (!keep && neighbor_old->enabled)
+                       system_del_neighbor(dev, neighbor_old);
+
+               free(neighbor_old);
+       }
+
+       if (node_new) {
+               if (!keep && ip->enabled)
+                       if (system_add_neighbor(dev, neighbor_new))
+                               neighbor_new->failed = true;
+
+               neighbor_new->enabled = ip->enabled;
+       }
+}
+
 static void
 interface_update_proto_route(struct vlist_tree *tree,
                             struct vlist_node *node_new,
@@ -1394,6 +1524,7 @@ void interface_ip_set_enabled(struct interface_ip_settings *ip, bool enabled)
 {
        struct device_addr *addr;
        struct device_route *route;
+       struct device_neighbor *neighbor;
        struct device *dev;
        struct interface *iface;
 
@@ -1439,7 +1570,6 @@ void interface_ip_set_enabled(struct interface_ip_settings *ip, bool enabled)
 
                if (!enable_route(ip, route))
                        _enabled = false;
-
                if (route->enabled == _enabled)
                        continue;
 
@@ -1453,6 +1583,19 @@ void interface_ip_set_enabled(struct interface_ip_settings *ip, bool enabled)
                route->enabled = _enabled;
        }
 
+       vlist_for_each_element(&ip->neighbor, neighbor, node) {
+               if (neighbor->enabled == enabled)
+                       continue;
+
+               if (enabled) {
+                       if(system_add_neighbor(dev, neighbor))
+                               neighbor->failed = true;
+               } else
+                       system_del_neighbor(dev, neighbor);
+
+               neighbor->enabled = enabled;
+       }
+
        struct device_prefix *c;
        struct device_prefix_assignment *a;
        list_for_each_entry(c, &prefixes, head)
@@ -1481,6 +1624,7 @@ interface_ip_update_start(struct interface_ip_settings *ip)
        vlist_update(&ip->route);
        vlist_update(&ip->addr);
        vlist_update(&ip->prefix);
+       vlist_update(&ip->neighbor);
 }
 
 void
@@ -1491,6 +1635,7 @@ interface_ip_update_complete(struct interface_ip_settings *ip)
        vlist_flush(&ip->route);
        vlist_flush(&ip->addr);
        vlist_flush(&ip->prefix);
+       vlist_flush(&ip->neighbor);
        interface_write_resolv_conf();
 }
 
@@ -1503,6 +1648,7 @@ interface_ip_flush(struct interface_ip_settings *ip)
        vlist_simple_flush_all(&ip->dns_search);
        vlist_flush_all(&ip->route);
        vlist_flush_all(&ip->addr);
+       vlist_flush_all(&ip->neighbor);
        vlist_flush_all(&ip->prefix);
 }
 
@@ -1514,6 +1660,7 @@ __interface_ip_init(struct interface_ip_settings *ip, struct interface *iface)
        vlist_simple_init(&ip->dns_search, struct dns_search_domain, node);
        vlist_simple_init(&ip->dns_servers, struct dns_server, node);
        vlist_init(&ip->route, route_cmp, interface_update_proto_route);
+       vlist_init(&ip->neighbor, neighbor_cmp, interface_update_proto_neighbor);
        vlist_init(&ip->addr, addr_cmp, interface_update_proto_addr);
        vlist_init(&ip->prefix, prefix_cmp, interface_update_prefix);
 }
index 21c6e9b24981d52ab0143401554f0f8e6e31025a..3f99eb9a48523c00525998d51bca4473aaac053a 100644 (file)
@@ -48,6 +48,9 @@ enum device_addr_flags {
 
        /* route overrides the default route type */
        DEVROUTE_TYPE           = (1 << 10),
+
+       /* neighbor mac address */
+       DEVNEIGH_MAC            = (1 << 11),
 };
 
 union if_addr {
@@ -106,6 +109,20 @@ struct device_route {
        union if_addr source;
 };
 
+struct device_neighbor {
+       struct vlist_node node;
+
+       bool failed;
+       bool proxy;
+       bool keep;
+       bool enabled;
+       bool router;
+
+       uint8_t macaddr[6];
+       enum device_addr_flags flags;
+       union if_addr addr;
+};
+
 struct device_addr {
        struct vlist_node node;
        bool enabled;
@@ -150,6 +167,7 @@ struct dns_search_domain {
 };
 
 extern const struct uci_blob_param_list route_attr_list;
+extern const struct uci_blob_param_list neighbor_attr_list;
 extern struct list_head prefixes;
 
 void interface_ip_init(struct interface *iface);
@@ -158,7 +176,7 @@ void interface_add_dns_search_list(struct interface_ip_settings *ip, struct blob
 void interface_write_resolv_conf(void);
 
 void interface_ip_add_route(struct interface *iface, struct blob_attr *attr, bool v6);
-
+void interface_ip_add_neighbor(struct interface *iface, struct blob_attr *attr, bool v6);
 void interface_ip_update_start(struct interface_ip_settings *ip);
 void interface_ip_update_complete(struct interface_ip_settings *ip);
 void interface_ip_flush(struct interface_ip_settings *ip);
index 098e0fc7e9f63e8d8830a0220f8aa9d8f44c6677..22738a9968fe80f0ff750cc4f05b6f27a089a21e 100644 (file)
@@ -82,6 +82,7 @@ struct interface_ip_settings {
        struct vlist_tree addr;
        struct vlist_tree route;
        struct vlist_tree prefix;
+       struct vlist_tree neighbor;
 
        struct vlist_simple_tree dns_servers;
        struct vlist_simple_tree dns_search;
@@ -146,6 +147,7 @@ struct interface {
        struct interface_ip_settings proto_ip;
        struct interface_ip_settings config_ip;
        struct vlist_tree host_routes;
+       struct vlist_tree host_neighbors;
 
        int metric;
        int dns_metric;
index 47a9568b290553c8e28ecb1efd34b9c3f98a2daf..07ec21ac440eac137eb764ff0fcdb06854bd1988 100644 (file)
@@ -413,6 +413,23 @@ proto_shell_parse_route_list(struct interface *iface, struct blob_attr *attr,
        }
 }
 
+static void
+proto_shell_parse_neighbor_list(struct interface *iface, struct blob_attr *attr,
+                               bool v6)
+{
+       struct blob_attr *cur;
+       int rem;
+
+       blobmsg_for_each_attr(cur, attr, rem) {
+               if (blobmsg_type(cur) != BLOBMSG_TYPE_TABLE) {
+                       DPRINTF("Ignore wrong neighbor type: %d\n", blobmsg_type(cur));
+                       continue;
+               }
+
+               interface_ip_add_neighbor(iface, cur, v6);
+       }
+}
+
 static void
 proto_shell_parse_data(struct interface *iface, struct blob_attr *attr)
 {
@@ -456,6 +473,8 @@ enum {
        NOTIFY_HOST,
        NOTIFY_DNS,
        NOTIFY_DNS_SEARCH,
+       NOTIFY_NEIGHBORS,
+       NOTIFY_NEIGHBORS6,
        __NOTIFY_LAST
 };
 
@@ -477,6 +496,8 @@ static const struct blobmsg_policy notify_attr[__NOTIFY_LAST] = {
        [NOTIFY_HOST] = { .name = "host", .type = BLOBMSG_TYPE_STRING },
        [NOTIFY_DNS] = { .name = "dns", .type = BLOBMSG_TYPE_ARRAY },
        [NOTIFY_DNS_SEARCH] = { .name = "dns_search", .type = BLOBMSG_TYPE_ARRAY },
+       [NOTIFY_NEIGHBORS]= {.name = "neighbor", .type = BLOBMSG_TYPE_ARRAY},
+       [NOTIFY_NEIGHBORS6]= {.name = "neighbor6", .type = BLOBMSG_TYPE_ARRAY},
 };
 
 static int
@@ -546,6 +567,12 @@ proto_shell_update_link(struct proto_shell_state *state, struct blob_attr *data,
        if ((cur = tb[NOTIFY_ROUTES6]) != NULL)
                proto_shell_parse_route_list(state->proto.iface, cur, true);
 
+       if ((cur = tb[NOTIFY_NEIGHBORS]) != NULL)
+               proto_shell_parse_neighbor_list(state->proto.iface, cur, false);
+
+       if ((cur = tb[NOTIFY_NEIGHBORS6]) != NULL)
+               proto_shell_parse_neighbor_list(state->proto.iface, cur, true);
+
        if ((cur = tb[NOTIFY_DNS]))
                interface_add_dns_server_list(&iface->proto_ip, cur);
 
index 31df91f3847098694c23512ad4ecb2c47519e277..87d337df07e9aa94b80ea53d050eadde791739d9 100644 (file)
@@ -64,6 +64,8 @@ proto_init_update() {
        PROTO_PREFIX6=
        PROTO_DNS=
        PROTO_DNS_SEARCH=
+       PROTO_NEIGHBOR=
+       PROTO_NEIGHBOR6=
        json_init
        json_add_int action 0
        [ -n "$ifname" -a "*" != "$ifname" ] && json_add_string "ifname" "$ifname"
@@ -133,6 +135,23 @@ proto_add_ipv6_address() {
        append PROTO_IP6ADDR "$address/$mask/$preferred/$valid/$offlink/$class"
 }
 
+proto_add_ipv4_neighbor(){
+       local address="$1"
+       local mac="$2"
+       local proxy="$3"
+
+       append PROTO_NEIGHBOR "$address/$mac/$proxy"
+}
+
+proto_add_ipv6_neighbor(){
+       local address="$1"
+       local mac="$2"
+       local proxy="$3"
+       local router="$4"
+
+       append PROTO_NEIGHBOR6 "$address/$mac/$proxy/$router"
+}
+
 proto_add_ipv4_route() {
        local target="$1"
        local mask="$2"
@@ -218,6 +237,43 @@ _proto_push_string() {
        json_add_string "" "$1"
 }
 
+_proto_push_ipv4_neighbor(){
+       local str="$1"
+       local address mac proxy
+
+       address="${str%%/*}"
+       str="${str#*/}"
+       mac="${str%%/*}"
+       str="${str#*/}"
+       proxy="${str%%/*}"
+
+       json_add_object ""
+       json_add_string ipaddr "$address"
+       [ -n "$mac" ] && json_add_string mac "$mac"
+       [ -n "$proxy" ] && json_add_boolean proxy "$proxy"
+       json_close_object
+}
+
+_proto_push_ipv6_neighbor(){
+       local str="$1"
+       local address mac proxy router
+
+       address="${str%%/*}"
+       str="${str#*/}"
+       mac="${str%%/*}"
+       str="${str#*/}"
+       proxy="${str%%/*}"
+       str="${str#*/}"
+       router="${str%%/*}"
+
+       json_add_object ""
+       json_add_string ipaddr "$address"
+       [ -n "$mac" ] && json_add_string mac "$mac"
+       [ -n "$proxy" ] && json_add_boolean proxy "$proxy"
+       [ -n "$router" ] && json_add_boolean router "$router"
+       json_close_object
+}
+
 _proto_push_route() {
        local str="$1";
        local target="${str%%/*}"
@@ -277,6 +333,8 @@ proto_send_update() {
        _proto_push_array "ip6prefix" "$PROTO_PREFIX6" _proto_push_string
        _proto_push_array "dns" "$PROTO_DNS" _proto_push_string
        _proto_push_array "dns_search" "$PROTO_DNS_SEARCH" _proto_push_string
+       _proto_push_array "neighbor" "$PROTO_NEIGHBOR" _proto_push_ipv4_neighbor
+       _proto_push_array "neighbor6" "$PROTO_NEIGHBOR6" _proto_push_ipv6_neighbor
        _proto_notify "$interface"
 }
 
index 11c8cccb0c53ed21d8e9b054d439d9fefebab929..58fd2d07937fc38d936c8b4c748108f85e95e88a 100644 (file)
@@ -181,6 +181,26 @@ static int system_route_msg(struct device *dev, struct device_route *route, cons
        return 0;
 }
 
+static int system_neighbor_msg(struct device *dev, struct device_neighbor *neighbor, const char *type)
+{
+       char addr[64];
+       int af = system_get_addr_family(neighbor->flags);
+       inet_ntop(af, &neighbor->addr.in , addr, sizeof(addr));
+
+       D(SYSTEM, "neigh %s %s%s%s %s\n", type, addr, neighbor->proxy ? "proxy " : "",
+               (neighbor->flags & DEVNEIGH_MAC) ? format_macaddr(neighbor->macaddr) : "",
+               neighbor->router ? "router": "");
+}
+int system_add_neighbor(struct device *dev, struct device_neighbor *neighbor)
+{
+       return system_neighbor_msg(dev, neighbor, "add");
+}
+
+int system_del_neighbor(struct device *dev, struct device_neighbor *neighbor)
+{
+       return system_neighbor_msg(dev, neighbor, "del");
+}
+
 int system_add_route(struct device *dev, struct device_route *route)
 {
        return system_route_msg(dev, route, "add");
index 82e9928c92e711e328c7844aadaeb9a6932a79b6..6a0105e304c391a82419cfa12fe72cfde989534b 100644 (file)
@@ -31,6 +31,7 @@
 #include <netinet/in.h>
 
 #include <linux/rtnetlink.h>
+#include <linux/neighbour.h>
 #include <linux/sockios.h>
 #include <linux/ip.h>
 #include <linux/if_addr.h>
@@ -1023,8 +1024,8 @@ void system_if_clear_state(struct device *dev)
 {
        static char buf[256];
        char *bridge;
-
        device_set_ifindex(dev, system_if_resolve(dev));
+
        if (dev->external || !dev->ifindex)
                return;
 
@@ -1046,6 +1047,8 @@ void system_if_clear_state(struct device *dev)
        system_if_clear_entries(dev, RTM_GETADDR, AF_INET);
        system_if_clear_entries(dev, RTM_GETROUTE, AF_INET6);
        system_if_clear_entries(dev, RTM_GETADDR, AF_INET6);
+       system_if_clear_entries(dev, RTM_GETNEIGH, AF_INET);
+       system_if_clear_entries(dev, RTM_GETNEIGH, AF_INET6);
        system_set_disable_ipv6(dev, "0");
 }
 
@@ -1930,6 +1933,51 @@ int system_del_address(struct device *dev, struct device_addr *addr)
        return system_addr(dev, addr, RTM_DELADDR);
 }
 
+static int system_neigh(struct device *dev, struct device_neighbor *neighbor, int cmd)
+{
+       int alen = ((neighbor->flags & DEVADDR_FAMILY) == DEVADDR_INET4) ? 4 : 16;
+       unsigned int flags = 0;
+       struct ndmsg ndm = {
+               .ndm_family = (alen == 4) ? AF_INET : AF_INET6,
+               .ndm_ifindex = dev->ifindex,
+               .ndm_state = NUD_PERMANENT,
+               .ndm_flags = (neighbor->proxy ? NTF_PROXY : 0) | (neighbor->router ? NTF_ROUTER : 0),
+       };
+       struct nl_msg *msg;
+
+       if (!dev)
+               return 1;
+
+       if (cmd == RTM_NEWNEIGH)
+               flags |= NLM_F_CREATE | NLM_F_REPLACE;
+
+       msg = nlmsg_alloc_simple(cmd, flags);
+
+       if (!msg)
+               return -1;
+
+       nlmsg_append(msg, &ndm, sizeof(ndm), 0);
+
+       nla_put(msg, NDA_DST, alen, &neighbor->addr);
+       if (neighbor->flags & DEVNEIGH_MAC)
+               nla_put(msg, NDA_LLADDR, sizeof(neighbor->macaddr), &neighbor->macaddr);
+
+
+       return system_rtnl_call(msg);
+}
+
+int system_add_neighbor(struct device *dev, struct device_neighbor *neighbor)
+{
+       return system_neigh(dev, neighbor, RTM_NEWNEIGH);
+}
+
+int system_del_neighbor(struct device *dev, struct device_neighbor *neighbor)
+{
+       int rval = system_neigh(dev, neighbor, RTM_DELNEIGH);
+       netifd_log_message(L_NOTICE,"return delete %d", rval);
+       return rval;
+}
+
 static int system_rt(struct device *dev, struct device_route *route, int cmd)
 {
        int alen = ((route->flags & DEVADDR_FAMILY) == DEVADDR_INET4) ? 4 : 16;
index 4d4cf6e443b38045866c9c93e2d81b8943b27713..9fefcaea2d400ed886d93c50007db10fdc30ab35 100644 (file)
--- a/system.h
+++ b/system.h
@@ -213,6 +213,9 @@ int system_add_route(struct device *dev, struct device_route *route);
 int system_del_route(struct device *dev, struct device_route *route);
 int system_flush_routes(void);
 
+int system_add_neighbor(struct device *dev, struct device_neighbor * neighbor);
+int system_del_neighbor(struct device *dev, struct device_neighbor * neighbor);
+
 bool system_resolve_rt_type(const char *type, unsigned int *id);
 bool system_resolve_rt_proto(const char *type, unsigned int *id);
 bool system_resolve_rt_table(const char *name, unsigned int *id);
diff --git a/ubus.c b/ubus.c
index 14688c25c876aedc17a215b0511dd67bdc10e7a4..e7cbfb96c7c25e61ba7ac729c240f2637c03ef8a 100644 (file)
--- a/ubus.c
+++ b/ubus.c
@@ -458,6 +458,43 @@ interface_ip_dump_address_list(struct interface_ip_settings *ip, bool v6, bool e
        }
 }
 
+static void
+interface_ip_dump_neighbor_list(struct interface_ip_settings *ip, bool enabled)
+{
+       struct device_neighbor *neighbor;
+       int buflen = 128;
+       char *buf;
+       void *r;
+       int af;
+
+       vlist_for_each_element(&ip->neighbor, neighbor, node) {
+               if (neighbor->enabled != enabled)
+                       continue;
+
+               if ((neighbor->flags & DEVADDR_FAMILY) == DEVADDR_INET4)
+                       af = AF_INET;
+               else
+                       af = AF_INET6;
+
+               r = blobmsg_open_table(&b, NULL);
+
+               if (neighbor->flags & DEVNEIGH_MAC)
+                       blobmsg_add_string(&b, "mac", format_macaddr(neighbor->macaddr));
+
+               buf = blobmsg_alloc_string_buffer(&b , "address", buflen);
+               inet_ntop(af, &neighbor->addr, buf, buflen);
+               blobmsg_add_string_buffer(&b);
+
+               if (neighbor->proxy)
+                       blobmsg_add_u32(&b, "proxy", neighbor->proxy);
+
+               if (neighbor->router)
+                       blobmsg_add_u32(&b, "router", neighbor->router);
+
+               blobmsg_close_table(&b, r);
+       }
+}
+
 static void
 interface_ip_dump_route_list(struct interface_ip_settings *ip, bool enabled)
 {
@@ -737,6 +774,10 @@ netifd_dump_status(struct interface *iface)
                interface_ip_dump_dns_search_list(&iface->config_ip, true);
                interface_ip_dump_dns_search_list(&iface->proto_ip, true);
                blobmsg_close_array(&b, a);
+               a = blobmsg_open_array(&b, "neighbors");
+               interface_ip_dump_neighbor_list(&iface->config_ip, true);
+               interface_ip_dump_neighbor_list(&iface->proto_ip, true);
+               blobmsg_close_array(&b, a);
 
                inactive = blobmsg_open_table(&b, "inactive");
                a = blobmsg_open_array(&b, "ipv4-address");
@@ -759,6 +800,10 @@ netifd_dump_status(struct interface *iface)
                interface_ip_dump_dns_search_list(&iface->config_ip, false);
                interface_ip_dump_dns_search_list(&iface->proto_ip, false);
                blobmsg_close_array(&b, a);
+               a = blobmsg_open_array(&b, "neighbors");
+               interface_ip_dump_neighbor_list(&iface->config_ip, false);
+               interface_ip_dump_neighbor_list(&iface->proto_ip, false);
+               blobmsg_close_array(&b, a);
                blobmsg_close_table(&b, inactive);
        }