summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--interface-ip.c14
-rw-r--r--interface-ip.h4
-rw-r--r--system-dummy.c6
-rw-r--r--system-linux.c103
-rw-r--r--system.h1
-rw-r--r--ubus.c3
6 files changed, 90 insertions, 41 deletions
diff --git a/interface-ip.c b/interface-ip.c
index bd6f164..715e498 100644
--- a/interface-ip.c
+++ b/interface-ip.c
@@ -39,6 +39,7 @@ enum {
ROUTE_TABLE,
ROUTE_SOURCE,
ROUTE_ONLINK,
+ ROUTE_TYPE,
__ROUTE_MAX
};
@@ -53,6 +54,7 @@ static const struct blobmsg_policy route_attr[__ROUTE_MAX] = {
[ROUTE_VALID] = { .name = "valid", .type = BLOBMSG_TYPE_INT32 },
[ROUTE_SOURCE] = { .name = "source", .type = BLOBMSG_TYPE_STRING },
[ROUTE_ONLINK] = { .name = "onlink", .type = BLOBMSG_TYPE_BOOL },
+ [ROUTE_TYPE] = { .name = "type", .type = BLOBMSG_TYPE_STRING }
};
const struct uci_blob_param_list route_attr_list = {
@@ -374,6 +376,14 @@ interface_ip_add_route(struct interface *iface, struct blob_attr *attr, bool v6)
route->valid_until = valid_until;
}
+ if ((cur = tb[ROUTE_TYPE]) != NULL) {
+ if (!system_resolve_rt_type(blobmsg_data(cur), &route->type)) {
+ DPRINTF("Failed to resolve routing type: %s\n", (char *) blobmsg_data(cur));
+ goto error;
+ }
+ route->flags |= DEVROUTE_TYPE;
+ }
+
vlist_add(&ip->route, &route->node, route);
return;
@@ -586,7 +596,8 @@ interface_update_proto_route(struct vlist_tree *tree,
if (node_old && node_new)
keep = !memcmp(&route_old->nexthop, &route_new->nexthop, sizeof(route_old->nexthop)) &&
- (route_old->mtu == route_new->mtu) && !route_old->failed;
+ (route_old->mtu == route_new->mtu) && (route_old->type == route_new->type) &&
+ !route_old->failed;
if (node_old) {
if (!(route_old->flags & DEVADDR_EXTERNAL) && route_old->enabled && !keep)
@@ -1223,7 +1234,6 @@ interface_ip_init(struct interface *iface)
__interface_ip_init(&iface->proto_ip, iface);
__interface_ip_init(&iface->config_ip, iface);
vlist_init(&iface->host_routes, route_cmp, interface_update_host_route);
-
}
static void
diff --git a/interface-ip.h b/interface-ip.h
index 93d55ee..a5612e5 100644
--- a/interface-ip.h
+++ b/interface-ip.h
@@ -45,6 +45,9 @@ enum device_addr_flags {
/* route is on-link */
DEVROUTE_ONLINK = (1 << 9),
+
+ /* route overrides the default route type */
+ DEVROUTE_TYPE = (1 << 10),
};
union if_addr {
@@ -107,6 +110,7 @@ struct device_route {
union if_addr nexthop;
int mtu;
+ unsigned int type;
time_t valid_until;
/* must be last */
diff --git a/system-dummy.c b/system-dummy.c
index bb94781..f2988f2 100644
--- a/system-dummy.c
+++ b/system-dummy.c
@@ -193,6 +193,12 @@ int system_flush_routes(void)
return 0;
}
+bool system_resolve_rt_type(const char *type, unsigned int *id)
+{
+ *id = 0;
+ return true;
+}
+
bool system_resolve_rt_table(const char *name, unsigned int *id)
{
*id = 0;
diff --git a/system-linux.c b/system-linux.c
index ad3adec..af54bfd 100644
--- a/system-linux.c
+++ b/system-linux.c
@@ -164,6 +164,46 @@ create_event_socket(struct event_socket *ev, int protocol,
return true;
}
+static bool
+system_rtn_aton(const char *src, unsigned int *dst)
+{
+ char *e;
+ unsigned int n;
+
+ if (!strcmp(src, "local"))
+ n = RTN_LOCAL;
+ else if (!strcmp(src, "nat"))
+ n = RTN_NAT;
+ else if (!strcmp(src, "broadcast"))
+ n = RTN_BROADCAST;
+ else if (!strcmp(src, "anycast"))
+ n = RTN_ANYCAST;
+ else if (!strcmp(src, "multicast"))
+ n = RTN_MULTICAST;
+ else if (!strcmp(src, "prohibit"))
+ n = RTN_PROHIBIT;
+ else if (!strcmp(src, "unreachable"))
+ n = RTN_UNREACHABLE;
+ else if (!strcmp(src, "blackhole"))
+ n = RTN_BLACKHOLE;
+ else if (!strcmp(src, "xresolve"))
+ n = RTN_XRESOLVE;
+ else if (!strcmp(src, "unicast"))
+ n = RTN_UNICAST;
+ else if (!strcmp(src, "throw"))
+ n = RTN_THROW;
+ else if (!strcmp(src, "failed_policy"))
+ n = RTN_FAILED_POLICY;
+ else {
+ n = strtoul(src, &e, 0);
+ if (!e || *e || e == src || n > 255)
+ return false;
+ }
+
+ *dst = n;
+ return true;
+}
+
int system_init(void)
{
static struct event_socket rtnl_event;
@@ -1281,9 +1321,6 @@ static int system_rt(struct device *dev, struct device_route *route, int cmd)
route->nexthop.in6.s6_addr32[2] ||
route->nexthop.in6.s6_addr32[3];
- unsigned char scope = (cmd == RTM_DELROUTE) ? RT_SCOPE_NOWHERE :
- (have_gw) ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK;
-
unsigned int table = (route->flags & (DEVROUTE_TABLE | DEVROUTE_SRCTABLE))
? route->table : RT_TABLE_MAIN;
@@ -1293,7 +1330,7 @@ static int system_rt(struct device *dev, struct device_route *route, int cmd)
.rtm_src_len = route->sourcemask,
.rtm_table = (table < 256) ? table : RT_TABLE_UNSPEC,
.rtm_protocol = (route->flags & DEVADDR_KERNEL) ? RTPROT_KERNEL : RTPROT_STATIC,
- .rtm_scope = scope,
+ .rtm_scope = RT_SCOPE_NOWHERE,
.rtm_type = (cmd == RTM_DELROUTE) ? 0: RTN_UNICAST,
.rtm_flags = (route->flags & DEVROUTE_ONLINK) ? RTNH_F_ONLINK : 0,
};
@@ -1306,6 +1343,23 @@ static int system_rt(struct device *dev, struct device_route *route, int cmd)
rtm.rtm_scope = RT_SCOPE_UNIVERSE;
rtm.rtm_type = RTN_UNREACHABLE;
}
+ else
+ rtm.rtm_scope = (have_gw) ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK;
+ }
+
+ if (route->flags & DEVROUTE_TYPE) {
+ rtm.rtm_type = route->type;
+ if (!(route->flags & (DEVROUTE_TABLE | DEVROUTE_SRCTABLE))) {
+ if (rtm.rtm_type == RTN_LOCAL || rtm.rtm_type == RTN_BROADCAST ||
+ rtm.rtm_type == RTN_NAT || rtm.rtm_type == RTN_ANYCAST)
+ rtm.rtm_table = RT_TABLE_LOCAL;
+ }
+
+ if (rtm.rtm_type == RTN_LOCAL || rtm.rtm_type == RTN_NAT)
+ rtm.rtm_scope = RT_SCOPE_HOST;
+ else if (rtm.rtm_type == RTN_BROADCAST || rtm.rtm_type == RTN_MULTICAST ||
+ rtm.rtm_type == RTN_ANYCAST)
+ rtm.rtm_scope = RT_SCOPE_LINK;
}
msg = nlmsg_alloc_simple(cmd, flags);
@@ -1379,6 +1433,11 @@ int system_flush_routes(void)
return 0;
}
+bool system_resolve_rt_type(const char *type, unsigned int *id)
+{
+ return system_rtn_aton(type, id);
+}
+
bool system_resolve_rt_table(const char *name, unsigned int *id)
{
FILE *f;
@@ -1564,41 +1623,7 @@ int system_flush_iprules(void)
bool system_resolve_iprule_action(const char *action, unsigned int *id)
{
- char *e;
- unsigned int n;
-
- if (!strcmp(action, "local"))
- n = RTN_LOCAL;
- else if (!strcmp(action, "nat"))
- n = RTN_NAT;
- else if (!strcmp(action, "broadcast"))
- n = RTN_BROADCAST;
- else if (!strcmp(action, "anycast"))
- n = RTN_ANYCAST;
- else if (!strcmp(action, "multicast"))
- n = RTN_MULTICAST;
- else if (!strcmp(action, "prohibit"))
- n = RTN_PROHIBIT;
- else if (!strcmp(action, "unreachable"))
- n = RTN_UNREACHABLE;
- else if (!strcmp(action, "blackhole"))
- n = RTN_BLACKHOLE;
- else if (!strcmp(action, "xresolve"))
- n = RTN_XRESOLVE;
- else if (!strcmp(action, "unicast"))
- n = RTN_UNICAST;
- else if (!strcmp(action, "throw"))
- n = RTN_THROW;
- else if (!strcmp(action, "failed_policy"))
- n = RTN_FAILED_POLICY;
- else {
- n = strtoul(action, &e, 0);
- if (!e || *e || e == action || n > 255)
- return false;
- }
-
- *id = n;
- return true;
+ return system_rtn_aton(action, id);
}
time_t system_get_rtime(void)
diff --git a/system.h b/system.h
index 76eee23..4c80eb0 100644
--- a/system.h
+++ b/system.h
@@ -128,6 +128,7 @@ 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);
+bool system_resolve_rt_type(const char *type, unsigned int *id);
bool system_resolve_rt_table(const char *name, unsigned int *id);
int system_del_ip_tunnel(const char *name);
diff --git a/ubus.c b/ubus.c
index cec2e88..9a573c6 100644
--- a/ubus.c
+++ b/ubus.c
@@ -486,6 +486,9 @@ interface_ip_dump_route_list(struct interface_ip_settings *ip, bool enabled)
inet_ntop(af, &route->nexthop, buf, buflen);
blobmsg_add_string_buffer(&b);
+ if (route->flags & DEVROUTE_TYPE)
+ blobmsg_add_u32(&b, "type", route->type);
+
if (route->flags & DEVROUTE_MTU)
blobmsg_add_u32(&b, "mtu", route->mtu);