return 0;
}
+static int tunnel_get_local_address(Tunnel *t, Link *link, union in_addr_union *ret) {
+ assert(t);
+
+ if (t->local_type < 0) {
+ if (ret)
+ *ret = t->local;
+ return 0;
+ }
+
+ return link_get_local_address(link, t->local_type, t->family, NULL, ret);
+}
+
static int netdev_ipip_sit_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
+ union in_addr_union local;
Tunnel *t;
int r;
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
}
- r = sd_netlink_message_append_in_addr(m, IFLA_IPTUN_LOCAL, &t->local.in);
+ r = tunnel_get_local_address(t, link, &local);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not find local address: %m");
+
+ r = sd_netlink_message_append_in_addr(m, IFLA_IPTUN_LOCAL, &local.in);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
}
static int netdev_gre_erspan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
+ union in_addr_union local;
uint32_t ikey = 0;
uint32_t okey = 0;
uint16_t iflags = 0;
return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_ERSPAN_INDEX attribute: %m");
}
- r = sd_netlink_message_append_in_addr(m, IFLA_GRE_LOCAL, &t->local.in);
+ r = tunnel_get_local_address(t, link, &local);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not find local address: %m");
+
+ r = sd_netlink_message_append_in_addr(m, IFLA_GRE_LOCAL, &local.in);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LOCAL attribute: %m");
}
static int netdev_ip6gre_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
+ union in_addr_union local;
uint32_t ikey = 0;
uint32_t okey = 0;
uint16_t iflags = 0;
return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LINK attribute: %m");
}
- r = sd_netlink_message_append_in6_addr(m, IFLA_GRE_LOCAL, &t->local.in6);
+ r = tunnel_get_local_address(t, link, &local);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not find local address: %m");
+
+ r = sd_netlink_message_append_in6_addr(m, IFLA_GRE_LOCAL, &local.in6);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LOCAL attribute: %m");
}
static int netdev_vti_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
+ union in_addr_union local;
uint32_t ikey, okey;
Tunnel *t;
int r;
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VTI_OKEY attribute: %m");
- r = netlink_message_append_in_addr_union(m, IFLA_VTI_LOCAL, t->family, &t->local);
+ r = tunnel_get_local_address(t, link, &local);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not find local address: %m");
+
+ r = netlink_message_append_in_addr_union(m, IFLA_VTI_LOCAL, t->family, &local);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VTI_LOCAL attribute: %m");
}
static int netdev_ip6tnl_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
+ union in_addr_union local;
uint8_t proto;
Tunnel *t;
int r;
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
}
- r = sd_netlink_message_append_in6_addr(m, IFLA_IPTUN_LOCAL, &t->local.in6);
+ r = tunnel_get_local_address(t, link, &local);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not find local address: %m");
+
+ r = sd_netlink_message_append_in6_addr(m, IFLA_IPTUN_LOCAL, &local.in6);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
return r;
}
+static int netdev_tunnel_is_ready_to_create(NetDev *netdev, Link *link) {
+ Tunnel *t;
+
+ assert(netdev);
+ assert(link);
+
+ t = TUNNEL(netdev);
+
+ assert(t);
+
+ return tunnel_get_local_address(t, link, NULL) >= 0;
+}
+
static int netdev_tunnel_verify(NetDev *netdev, const char *filename) {
Tunnel *t;
if (t->assign_to_loopback)
t->independent = true;
+ if (t->independent && t->local_type >= 0)
+ return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
+ "The local address cannot be '%s' when Independent= or AssignToLoopback= is enabled, ignoring.",
+ strna(netdev_local_address_type_to_string(t->local_type)));
+
return 0;
}
-int config_parse_tunnel_address(
+int config_parse_tunnel_local_address(
const char *unit,
const char *filename,
unsigned line,
void *data,
void *userdata) {
+ union in_addr_union buffer = IN_ADDR_NULL;
+ NetDevLocalAddressType type;
Tunnel *t = userdata;
- union in_addr_union *addr = data, buffer;
int r, f;
assert(filename);
assert(lvalue);
assert(rvalue);
- assert(data);
+ assert(userdata);
+
+ if (isempty(rvalue) || streq(rvalue, "any")) {
+ /* Unset the previous assignment. */
+ t->local = IN_ADDR_NULL;
+ t->local_type = _NETDEV_LOCAL_ADDRESS_TYPE_INVALID;
+
+ /* If the remote address is not specified, also clear the address family. */
+ if (!in_addr_is_set(t->family, &t->remote))
+ t->family = AF_UNSPEC;
+ return 0;
+ }
+
+ type = netdev_local_address_type_from_string(rvalue);
+ if (IN_SET(type, NETDEV_LOCAL_ADDRESS_IPV4LL, NETDEV_LOCAL_ADDRESS_DHCP4))
+ f = AF_INET;
+ else if (IN_SET(type, NETDEV_LOCAL_ADDRESS_IPV6LL, NETDEV_LOCAL_ADDRESS_DHCP6, NETDEV_LOCAL_ADDRESS_SLAAC))
+ f = AF_INET6;
+ else {
+ type = _NETDEV_LOCAL_ADDRESS_TYPE_INVALID;
+ r = in_addr_from_string_auto(rvalue, &f, &buffer);
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Tunnel address \"%s\" invalid, ignoring assignment: %m", rvalue);
+ return 0;
+ }
+ }
+
+ if (t->family != AF_UNSPEC && t->family != f) {
+ log_syntax(unit, LOG_WARNING, filename, line, 0,
+ "Address family does not match the previous assignment, ignoring assignment: %s", rvalue);
+ return 0;
+ }
- /* This is used to parse addresses on both local and remote ends of the tunnel.
- * Address families must match.
- *
- * "any" is a special value which means that the address is unspecified.
- */
+ t->family = f;
+ t->local = buffer;
+ t->local_type = type;
+ return 0;
+}
+
+int config_parse_tunnel_remote_address(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ union in_addr_union buffer;
+ Tunnel *t = userdata;
+ int r, f;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(userdata);
- if (streq(rvalue, "any")) {
- *addr = IN_ADDR_NULL;
+ if (isempty(rvalue) || streq(rvalue, "any")) {
+ /* Unset the previous assignment. */
+ t->remote = IN_ADDR_NULL;
- /* As a special case, if both the local and remote addresses are
- * unspecified, also clear the address family. */
- if (!in_addr_is_set(t->family, &t->local) &&
- !in_addr_is_set(t->family, &t->remote))
+ /* If the local address is not specified, also clear the address family. */
+ if (t->local_type == _NETDEV_LOCAL_ADDRESS_TYPE_INVALID &&
+ !in_addr_is_set(t->family, &t->local))
t->family = AF_UNSPEC;
return 0;
}
if (t->family != AF_UNSPEC && t->family != f) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
- "Tunnel addresses incompatible, ignoring assignment: %s", rvalue);
+ "Address family does not match the previous assignment, ignoring assignment: %s", rvalue);
return 0;
}
t->family = f;
- *addr = buffer;
+ t->remote = buffer;
return 0;
}
assert(t);
+ t->local_type = _NETDEV_LOCAL_ADDRESS_TYPE_INVALID;
t->pmtudisc = true;
t->fou_encap_type = NETDEV_FOO_OVER_UDP_ENCAP_DIRECT;
t->isatap = -1;
.sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
.fill_message_create = netdev_ipip_sit_fill_message_create,
.create_type = NETDEV_CREATE_STACKED,
+ .is_ready_to_create = netdev_tunnel_is_ready_to_create,
.config_verify = netdev_tunnel_verify,
.iftype = ARPHRD_TUNNEL,
};
.sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
.fill_message_create = netdev_ipip_sit_fill_message_create,
.create_type = NETDEV_CREATE_STACKED,
+ .is_ready_to_create = netdev_tunnel_is_ready_to_create,
.config_verify = netdev_tunnel_verify,
.iftype = ARPHRD_SIT,
};
.sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
.fill_message_create = netdev_vti_fill_message_create,
.create_type = NETDEV_CREATE_STACKED,
+ .is_ready_to_create = netdev_tunnel_is_ready_to_create,
.config_verify = netdev_tunnel_verify,
.iftype = ARPHRD_TUNNEL,
};
.sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
.fill_message_create = netdev_vti_fill_message_create,
.create_type = NETDEV_CREATE_STACKED,
+ .is_ready_to_create = netdev_tunnel_is_ready_to_create,
.config_verify = netdev_tunnel_verify,
.iftype = ARPHRD_TUNNEL6,
};
.sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
.fill_message_create = netdev_gre_erspan_fill_message_create,
.create_type = NETDEV_CREATE_STACKED,
+ .is_ready_to_create = netdev_tunnel_is_ready_to_create,
.config_verify = netdev_tunnel_verify,
.iftype = ARPHRD_IPGRE,
};
.sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
.fill_message_create = netdev_gre_erspan_fill_message_create,
.create_type = NETDEV_CREATE_STACKED,
+ .is_ready_to_create = netdev_tunnel_is_ready_to_create,
.config_verify = netdev_tunnel_verify,
.iftype = ARPHRD_ETHER,
.generate_mac = true,
.sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
.fill_message_create = netdev_ip6gre_fill_message_create,
.create_type = NETDEV_CREATE_STACKED,
+ .is_ready_to_create = netdev_tunnel_is_ready_to_create,
.config_verify = netdev_tunnel_verify,
.iftype = ARPHRD_IP6GRE,
};
.sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
.fill_message_create = netdev_ip6gre_fill_message_create,
.create_type = NETDEV_CREATE_STACKED,
+ .is_ready_to_create = netdev_tunnel_is_ready_to_create,
.config_verify = netdev_tunnel_verify,
.iftype = ARPHRD_ETHER,
.generate_mac = true,
.sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
.fill_message_create = netdev_ip6tnl_fill_message_create,
.create_type = NETDEV_CREATE_STACKED,
+ .is_ready_to_create = netdev_tunnel_is_ready_to_create,
.config_verify = netdev_tunnel_verify,
.iftype = ARPHRD_TUNNEL6,
};
.sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
.fill_message_create = netdev_gre_erspan_fill_message_create,
.create_type = NETDEV_CREATE_STACKED,
+ .is_ready_to_create = netdev_tunnel_is_ready_to_create,
.config_verify = netdev_tunnel_verify,
.iftype = ARPHRD_ETHER,
.generate_mac = true,