Message ID | 1555055788-14308-1-git-send-email-meurisalexander@gmail.com |
---|---|
State | Accepted |
Headers | show |
Series | [OpenWrt-Devel,netifd] interface: add neighbor config support | expand |
> Op 12 apr. 2019, om 09:56 heeft Alexander Meuris <meurisalexander@gmail.com> het volgende geschreven: > > From: meurisa <alexander.meuris@technicolor.com> > > 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 Out of curiosity: what use-case is served with this change ? > > 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 | 19 +++++- > interface-ip.c | 149 +++++++++++++++++++++++++++++++++++++++++++++++- > interface-ip.h | 20 ++++++- > interface.h | 2 + > proto-shell.c | 27 +++++++++ > scripts/netifd-proto.sh | 58 +++++++++++++++++++ > system-dummy.c | 20 +++++++ > system-linux.c | 50 +++++++++++++++- > system.h | 3 + > ubus.c | 45 +++++++++++++++ > 10 files changed, 388 insertions(+), 5 deletions(-) > > diff --git a/config.c b/config.c > index be10379..843c53f 100644 > --- a/config.c > +++ b/config.c > @@ -144,6 +144,17 @@ config_parse_route(struct uci_section *s, bool 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) > { > void *rule; > @@ -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(); > diff --git a/interface-ip.c b/interface-ip.c > index 2a183ac..e996aaa 100644 > --- a/interface-ip.c > +++ b/interface-ip.c > @@ -20,6 +20,10 @@ > #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; > @@ -299,6 +325,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) > { > struct interface_ip_settings *ip; > @@ -429,6 +513,14 @@ addr_cmp(const void *k1, const void *k2, void *ptr) > } > > 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) > { > const struct device_route *r1 = k1, *r2 = k2; > @@ -628,6 +720,44 @@ enable_route(struct interface_ip_settings *ip, struct device_route *route) > } > > 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, > struct vlist_node *node_old) > @@ -1402,6 +1532,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; > > @@ -1447,7 +1578,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; > > @@ -1461,6 +1591,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) > @@ -1489,6 +1632,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 > @@ -1499,6 +1643,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(); > } > > @@ -1511,6 +1656,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); > } > > @@ -1522,6 +1668,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); > } > diff --git a/interface-ip.h b/interface-ip.h > index 21c6e9b..3f99eb9 100644 > --- a/interface-ip.h > +++ b/interface-ip.h > @@ -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); > diff --git a/interface.h b/interface.h > index 6f10484..3c0c9ed 100644 > --- a/interface.h > +++ b/interface.h > @@ -84,6 +84,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; > @@ -150,6 +151,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; > diff --git a/proto-shell.c b/proto-shell.c > index 47a9568..07ec21a 100644 > --- a/proto-shell.c > +++ b/proto-shell.c > @@ -414,6 +414,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) > { > struct blob_attr *cur; > @@ -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); > > diff --git a/scripts/netifd-proto.sh b/scripts/netifd-proto.sh > index 31df91f..87d337d 100644 > --- a/scripts/netifd-proto.sh > +++ b/scripts/netifd-proto.sh > @@ -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" > } > > diff --git a/system-dummy.c b/system-dummy.c > index 11c8ccc..58fd2d0 100644 > --- a/system-dummy.c > +++ b/system-dummy.c > @@ -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"); > diff --git a/system-linux.c b/system-linux.c > index 82e9928..6a0105e 100644 > --- a/system-linux.c > +++ b/system-linux.c > @@ -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; > diff --git a/system.h b/system.h > index 4d4cf6e..9fefcae 100644 > --- 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 32bc1a3..0e86b61 100644 > --- a/ubus.c > +++ b/ubus.c > @@ -459,6 +459,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) > { > struct device_route *route; > @@ -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); > } > > -- > 2.7.4 > > > _______________________________________________ > openwrt-devel mailing list > openwrt-devel@lists.openwrt.org > https://lists.openwrt.org/mailman/listinfo/openwrt-devel
On Sat, Apr 13, 2019 at 11:17 AM Paul Oranje <por@oranjevos.nl> wrote: > > > > Op 12 apr. 2019, om 09:56 heeft Alexander Meuris <meurisalexander@gmail.com> het volgende geschreven: > > > > From: meurisa <alexander.meuris@technicolor.com> > > > > 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 > Out of curiosity: what use-case is served with this change ? Proxy ARP entries can be usefull in some VPN scenarios while static ARP entries can be usefull for trouble shooting or if a device is unable to learn a mac address dynamically whatever the reason may be > > > > > 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 | 19 +++++- > > interface-ip.c | 149 +++++++++++++++++++++++++++++++++++++++++++++++- > > interface-ip.h | 20 ++++++- > > interface.h | 2 + > > proto-shell.c | 27 +++++++++ > > scripts/netifd-proto.sh | 58 +++++++++++++++++++ > > system-dummy.c | 20 +++++++ > > system-linux.c | 50 +++++++++++++++- > > system.h | 3 + > > ubus.c | 45 +++++++++++++++ > > 10 files changed, 388 insertions(+), 5 deletions(-) > > > > diff --git a/config.c b/config.c > > index be10379..843c53f 100644 > > --- a/config.c > > +++ b/config.c > > @@ -144,6 +144,17 @@ config_parse_route(struct uci_section *s, bool 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) > > { > > void *rule; > > @@ -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(); > > diff --git a/interface-ip.c b/interface-ip.c > > index 2a183ac..e996aaa 100644 > > --- a/interface-ip.c > > +++ b/interface-ip.c > > @@ -20,6 +20,10 @@ > > #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; > > @@ -299,6 +325,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) > > { > > struct interface_ip_settings *ip; > > @@ -429,6 +513,14 @@ addr_cmp(const void *k1, const void *k2, void *ptr) > > } > > > > 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) > > { > > const struct device_route *r1 = k1, *r2 = k2; > > @@ -628,6 +720,44 @@ enable_route(struct interface_ip_settings *ip, struct device_route *route) > > } > > > > 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, > > struct vlist_node *node_old) > > @@ -1402,6 +1532,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; > > > > @@ -1447,7 +1578,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; > > > > @@ -1461,6 +1591,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) > > @@ -1489,6 +1632,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 > > @@ -1499,6 +1643,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(); > > } > > > > @@ -1511,6 +1656,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); > > } > > > > @@ -1522,6 +1668,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); > > } > > diff --git a/interface-ip.h b/interface-ip.h > > index 21c6e9b..3f99eb9 100644 > > --- a/interface-ip.h > > +++ b/interface-ip.h > > @@ -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); > > diff --git a/interface.h b/interface.h > > index 6f10484..3c0c9ed 100644 > > --- a/interface.h > > +++ b/interface.h > > @@ -84,6 +84,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; > > @@ -150,6 +151,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; > > diff --git a/proto-shell.c b/proto-shell.c > > index 47a9568..07ec21a 100644 > > --- a/proto-shell.c > > +++ b/proto-shell.c > > @@ -414,6 +414,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) > > { > > struct blob_attr *cur; > > @@ -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); > > > > diff --git a/scripts/netifd-proto.sh b/scripts/netifd-proto.sh > > index 31df91f..87d337d 100644 > > --- a/scripts/netifd-proto.sh > > +++ b/scripts/netifd-proto.sh > > @@ -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" > > } > > > > diff --git a/system-dummy.c b/system-dummy.c > > index 11c8ccc..58fd2d0 100644 > > --- a/system-dummy.c > > +++ b/system-dummy.c > > @@ -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"); > > diff --git a/system-linux.c b/system-linux.c > > index 82e9928..6a0105e 100644 > > --- a/system-linux.c > > +++ b/system-linux.c > > @@ -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; > > diff --git a/system.h b/system.h > > index 4d4cf6e..9fefcae 100644 > > --- 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 32bc1a3..0e86b61 100644 > > --- a/ubus.c > > +++ b/ubus.c > > @@ -459,6 +459,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) > > { > > struct device_route *route; > > @@ -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); > > } > > > > -- > > 2.7.4 > > > > > > _______________________________________________ > > openwrt-devel mailing list > > openwrt-devel@lists.openwrt.org > > https://lists.openwrt.org/mailman/listinfo/openwrt-devel >
diff --git a/config.c b/config.c index be10379..843c53f 100644 --- a/config.c +++ b/config.c @@ -144,6 +144,17 @@ config_parse_route(struct uci_section *s, bool 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) { void *rule; @@ -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(); diff --git a/interface-ip.c b/interface-ip.c index 2a183ac..e996aaa 100644 --- a/interface-ip.c +++ b/interface-ip.c @@ -20,6 +20,10 @@ #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; @@ -299,6 +325,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) { struct interface_ip_settings *ip; @@ -429,6 +513,14 @@ addr_cmp(const void *k1, const void *k2, void *ptr) } 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) { const struct device_route *r1 = k1, *r2 = k2; @@ -628,6 +720,44 @@ enable_route(struct interface_ip_settings *ip, struct device_route *route) } 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, struct vlist_node *node_old) @@ -1402,6 +1532,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; @@ -1447,7 +1578,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; @@ -1461,6 +1591,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) @@ -1489,6 +1632,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 @@ -1499,6 +1643,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(); } @@ -1511,6 +1656,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); } @@ -1522,6 +1668,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); } diff --git a/interface-ip.h b/interface-ip.h index 21c6e9b..3f99eb9 100644 --- a/interface-ip.h +++ b/interface-ip.h @@ -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); diff --git a/interface.h b/interface.h index 6f10484..3c0c9ed 100644 --- a/interface.h +++ b/interface.h @@ -84,6 +84,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; @@ -150,6 +151,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; diff --git a/proto-shell.c b/proto-shell.c index 47a9568..07ec21a 100644 --- a/proto-shell.c +++ b/proto-shell.c @@ -414,6 +414,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) { struct blob_attr *cur; @@ -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); diff --git a/scripts/netifd-proto.sh b/scripts/netifd-proto.sh index 31df91f..87d337d 100644 --- a/scripts/netifd-proto.sh +++ b/scripts/netifd-proto.sh @@ -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" } diff --git a/system-dummy.c b/system-dummy.c index 11c8ccc..58fd2d0 100644 --- a/system-dummy.c +++ b/system-dummy.c @@ -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"); diff --git a/system-linux.c b/system-linux.c index 82e9928..6a0105e 100644 --- a/system-linux.c +++ b/system-linux.c @@ -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; diff --git a/system.h b/system.h index 4d4cf6e..9fefcae 100644 --- 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 32bc1a3..0e86b61 100644 --- a/ubus.c +++ b/ubus.c @@ -459,6 +459,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) { struct device_route *route; @@ -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); }