Files
bpf-developer-tutorial/bcc-documents/kernel_config.html

271 lines
25 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE HTML>
<html lang="en" class="light" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Kernel Configuration for BPF Features - bpf-developer-tutorial</title>
<!-- Custom HTML head -->
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="icon" href="../favicon.svg">
<link rel="shortcut icon" href="../favicon.png">
<link rel="stylesheet" href="../css/variables.css">
<link rel="stylesheet" href="../css/general.css">
<link rel="stylesheet" href="../css/chrome.css">
<link rel="stylesheet" href="../css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="../fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="../highlight.css">
<link rel="stylesheet" href="../tomorrow-night.css">
<link rel="stylesheet" href="../ayu-highlight.css">
<!-- Custom theme stylesheets -->
</head>
<body class="sidebar-visible no-js">
<div id="body-container">
<!-- Provide site root to javascript -->
<script>
var path_to_root = "../";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
</script>
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
var html = document.querySelector('html');
html.classList.remove('light')
html.classList.add(theme);
var body = document.querySelector('body');
body.classList.remove('no-js')
body.classList.add('js');
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
var body = document.querySelector('body');
var sidebar = null;
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
body.classList.remove('sidebar-visible');
body.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox">
<ol class="chapter"><li class="chapter-item expanded affix "><a href="../https://github.com/eunomia-bpf/bpf-developer-tutorial.html">https://github.com/eunomia-bpf/bpf-developer-tutorial</a></li><li class="chapter-item expanded affix "><li class="part-title">入门文档</li><li class="chapter-item expanded "><a href="../0-introduce/index.html"><strong aria-hidden="true">1.</strong> lesson 0-introduce</a></li><li class="chapter-item expanded "><a href="../1-helloworld/index.html"><strong aria-hidden="true">2.</strong> lesson 1-helloworld</a></li><li class="chapter-item expanded "><a href="../2-kprobe-unlink/index.html"><strong aria-hidden="true">3.</strong> lesson 2-kprobe-unlink</a></li><li class="chapter-item expanded "><a href="../3-fentry-unlink/index.html"><strong aria-hidden="true">4.</strong> lesson 3-fentry-unlink</a></li><li class="chapter-item expanded "><a href="../4-opensnoop/index.html"><strong aria-hidden="true">5.</strong> lesson 4-opensnoop</a></li><li class="chapter-item expanded "><a href="../5-uprobe-bashreadline/index.html"><strong aria-hidden="true">6.</strong> lesson 5-uprobe-bashreadline</a></li><li class="chapter-item expanded "><a href="../6-sigsnoop/index.html"><strong aria-hidden="true">7.</strong> lesson 6-sigsnoop</a></li><li class="chapter-item expanded "><a href="../7-execsnoop/index.html"><strong aria-hidden="true">8.</strong> lesson 7-execsnoop</a></li><li class="chapter-item expanded "><a href="../8-exitsnoop/index.html"><strong aria-hidden="true">9.</strong> lesson 8-execsnoop</a></li><li class="chapter-item expanded "><a href="../9-runqlat/index.html"><strong aria-hidden="true">10.</strong> lesson 9-runqlat</a></li><li class="chapter-item expanded "><a href="../10-hardirqs/index.html"><strong aria-hidden="true">11.</strong> lesson 10-hardirqs</a></li><li class="chapter-item expanded affix "><li class="part-title">进阶文档和示例</li><li class="chapter-item expanded "><a href="../11-bootstrap/index.html"><strong aria-hidden="true">12.</strong> lesson 11-bootstrap</a></li><li class="chapter-item expanded "><a href="../12-profile/index.html"><strong aria-hidden="true">13.</strong> lesson 12-profile</a></li><li class="chapter-item expanded "><a href="../13-tcpconnlat/index.html"><strong aria-hidden="true">14.</strong> lesson 13-tcpconnlat</a></li><li class="chapter-item expanded "><a href="../14-tcpstates/index.html"><strong aria-hidden="true">15.</strong> lesson 14-tcpstates</a></li><li class="chapter-item expanded "><a href="../15-javagc/index.html"><strong aria-hidden="true">16.</strong> lesson 15-javagc</a></li><li class="chapter-item expanded "><a href="../16-memleak/index.html"><strong aria-hidden="true">17.</strong> lesson 16-memleak</a></li><li class="chapter-item expanded "><a href="../17-biopattern/index.html"><strong aria-hidden="true">18.</strong> lesson 17-biopattern</a></li><li class="chapter-item expanded "><a href="../18-further-reading/index.html"><strong aria-hidden="true">19.</strong> lesson 18-further-reading</a></li><li class="chapter-item expanded "><a href="../19-lsm-connect/index.html"><strong aria-hidden="true">20.</strong> lesson 19-lsm-connect</a></li><li class="chapter-item expanded "><a href="../20-tc/index.html"><strong aria-hidden="true">21.</strong> lesson 20-tc</a></li><li class="chapter-item expanded "><a href="../21-xdp/index.html"><strong aria-hidden="true">22.</strong> lesson 21-xdp</a></li><li class="chapter-item expanded affix "><li class="part-title">高级主题</li><li class="chapter-item expanded "><a href="../22-android/index.html"><strong aria-hidden="true">23.</strong> 在 Android 上使用 eBPF 程序</a></li><li class="chapter-item expanded "><a href="../30-sslsniff/index.html"><strong aria-hidden="true">24.</strong> 使用 uprobe 捕获多种库的 SSL/TLS 明文数据</a></li><li class="chapter-item expanded "><a href="../23-http/index.html"><strong aria-hidden="true">25.</strong> 使用 eBPF socket filter 或 syscall trace 追踪 HTTP 请求和其他七层协议</a></li><li class="chapter-item expanded "><a href="../29-sockops/index.html"><strong aria-hidden="true">26.</strong> 使用 sockops 加速网络请求转发</a></li><li class="chapter-item expanded "><a href="../24-hide/index.html"><strong aria-hidden="true">27.</strong> 使用 eBPF 隐藏进程或文件信息</a></li><li class="chapter-item expanded "><a href="../25-signal/index.html"><strong aria-hidden="true">28.</strong> 使用 bpf_send_signal 发送信号终止进程</a></li><li class="chapter-item expanded "><a href="../26-sudo/index.html"><strong aria-hidden="true">29.</strong> 使用 eBPF 添加 sudo 用户</a></li><li class="chapter-item expanded "><a href="../27-replace/index.html"><strong aria-hidden="true">30.</strong> 使用 eBPF 替换任意程序读取或写入的文本</a></li><li class="chapter-item expanded "><a href="../28-detach/index.html"><strong aria-hidden="true">31.</strong> BPF 的生命周期:使用 Detached 模式在用户态应用退出后持续运行 eBPF 程序</a></li><li class="chapter-item expanded "><a href="../18-further-reading/ebpf-security.zh.html"><strong aria-hidden="true">32.</strong> eBPF 运行时的安全性与面临的挑战</a></li><li class="chapter-item expanded "><a href="../34-syscall/index.html"><strong aria-hidden="true">33.</strong> 使用 eBPF 修改系统调用参数</a></li><li class="chapter-item expanded "><a href="../36-userspace-ebpf/index.html"><strong aria-hidden="true">34.</strong> 用户空间 eBPF 运行时:深度解析与应用实践</a></li><li class="chapter-item expanded affix "><li class="part-title">bcc 和 bpftrace 教程与文档</li><li class="chapter-item expanded "><a href="../bcc-documents/kernel-versions.html"><strong aria-hidden="true">35.</strong> BPF Features by Linux Kernel Version</a></li><li class="chapter-item expanded "><a href="../bcc-documents/kernel_config.html" class="active"><strong aria-hidden="true">36.</strong> Kernel Configuration for BPF Features</a></li><li class="chapter-item expanded "><a href="../bcc-documents/reference_guide.html"><strong aria-hidden="true">37.</strong> bcc Reference Guide</a></li><li class="chapter-item expanded "><a href="../bcc-documents/special_filtering.html"><strong aria-hidden="true">38.</strong> Special Filtering</a></li><li class="chapter-item expanded "><a href="../bcc-documents/tutorial.html"><strong aria-hidden="true">39.</strong> bcc Tutorial</a></li><li class="chapter-item expanded "><a href="../bcc-documents/tutorial_bcc_python_developer.html"><strong aria-hidden="true">40.</strong> bcc Python Developer Tutorial</a></li><li class="chapter-item expanded "><a href="../bpftrace-tutorial/index.html"><strong aria-hidden="true">41.</strong> bpftrace Tutorial</a></li></ol>
</div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<!-- Track and set sidebar scroll position -->
<script>
var sidebarScrollbox = document.querySelector('#sidebar .sidebar-scrollbox');
sidebarScrollbox.addEventListener('click', function(e) {
if (e.target.tagName === 'A') {
sessionStorage.setItem('sidebar-scroll', sidebarScrollbox.scrollTop);
}
}, { passive: true });
var sidebarScrollTop = sessionStorage.getItem('sidebar-scroll');
sessionStorage.removeItem('sidebar-scroll');
if (sidebarScrollTop) {
// preserve sidebar scroll position when navigating via links within sidebar
sidebarScrollbox.scrollTop = sidebarScrollTop;
} else {
// scroll sidebar to current active section when navigating via "next/previous chapter" buttons
var activeSection = document.querySelector('#sidebar .active');
if (activeSection) {
activeSection.scrollIntoView({ block: 'center' });
}
}
</script>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">bpf-developer-tutorial</h1>
<div class="right-buttons">
<a href="../print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="bpf-特性的内核配置"><a class="header" href="#bpf-特性的内核配置">BPF 特性的内核配置</a></h1>
<h2 id="与-bpf-相关的内核配置"><a class="header" href="#与-bpf-相关的内核配置">与 BPF 相关的内核配置</a></h2>
<div class="table-wrapper"><table><thead><tr><th style="text-align: left">功能</th><th style="text-align: left">内核配置</th><th style="text-align: left">描述</th></tr></thead><tbody>
<tr><td style="text-align: left"><strong>基础</strong></td><td style="text-align: left">CONFIG_BPF_SYSCALL</td><td style="text-align: left">启用 bpf() 系统调用</td></tr>
<tr><td style="text-align: left"></td><td style="text-align: left">CONFIG_BPF_JIT</td><td style="text-align: left">BPF 程序通常由 BPF 解释器处理。此选项允许内核在加载程序时生成本地代码。这将显著加速 BPF 程序的处理</td></tr>
<tr><td style="text-align: left"></td><td style="text-align: left">CONFIG_HAVE_BPF_JIT</td><td style="text-align: left">启用 BPF 即时编译器</td></tr>
<tr><td style="text-align: left"></td><td style="text-align: left">CONFIG_HAVE_EBPF_JIT</td><td style="text-align: left">扩展 BPF JIT (eBPF)</td></tr>
<tr><td style="text-align: left"></td><td style="text-align: left">CONFIG_HAVE_CBPF_JIT</td><td style="text-align: left">经典 BPF JIT (cBPF)</td></tr>
<tr><td style="text-align: left"></td><td style="text-align: left">CONFIG_MODULES</td><td style="text-align: left">启用可加载内核模块的构建</td></tr>
<tr><td style="text-align: left"></td><td style="text-align: left">CONFIG_BPF</td><td style="text-align: left">BPF VM 解释器</td></tr>
<tr><td style="text-align: left"></td><td style="text-align: left">CONFIG_BPF_EVENTS</td><td style="text-align: left">允许用户将 BPF 程序附加到 kprobe、uprobe 和 tracepoint 事件上</td></tr>
<tr><td style="text-align: left"></td><td style="text-align: left">CONFIG_PERF_EVENTS</td><td style="text-align: left">内核性能事件和计数器</td></tr>
<tr><td style="text-align: left"></td><td style="text-align: left">CONFIG_HAVE_PERF_EVENTS</td><td style="text-align: left">启用性能事件</td></tr>
<tr><td style="text-align: left"></td><td style="text-align: left">CONFIG_PROFILING</td><td style="text-align: left">启用分析器使用的扩展分析支持机制</td></tr>
<tr><td style="text-align: left"><strong>BTF</strong></td><td style="text-align: left">CONFIG_DEBUG_INFO_BTF</td><td style="text-align: left">从 DWARF 调试信息生成去重的 BTF 类型信息</td></tr>
<tr><td style="text-align: left"></td><td style="text-align: left">CONFIG_PAHOLE_HAS_SPLIT_BTF</td><td style="text-align: left">为每个选定的内核模块生成 BTF</td></tr>
<tr><td style="text-align: left"></td><td style="text-align: left">CONFIG_DEBUG_INFO_BTF_MODULES</td><td style="text-align: left">为内核模块生成紧凑的分割 BTF 类型信息</td></tr>
<tr><td style="text-align: left"><strong>安全</strong></td><td style="text-align: left">CONFIG_BPF_JIT_ALWAYS_ON</td><td style="text-align: left">启用 BPF JIT 并删除 BPF 解释器以避免猜测执行</td></tr>
<tr><td style="text-align: left"></td><td style="text-align: left">CONFIG_BPF_UNPRIV_DEFAULT_OFF</td><td style="text-align: left">通过设置默认禁用非特权 BPF</td></tr>
<tr><td style="text-align: left"><strong>Cgroup</strong></td><td style="text-align: left">CONFIG_CGROUP_BPF</td><td style="text-align: left">支持将 BPF 程序附加到 cgroup 上</td></tr>
<tr><td style="text-align: left"><strong>网络</strong></td><td style="text-align: left">CONFIG_BPFILTER</td><td style="text-align: left">基于 BPF 的数据包过滤框架 (BPFILTER)</td></tr>
<tr><td style="text-align: left"></td><td style="text-align: left">CONFIG_BPFILTER_UMH</td><td style="text-align: left">使用内嵌的用户模式助手构建 bpfilter 内核模块</td></tr>
<tr><td style="text-align: left"></td><td style="text-align: left">CONFIG_NET_CLS_BPF</td><td style="text-align: left">基于可编程 BPF (JIT'ed) 过滤器进行数据包分类的基于 BPF 的分类器的替代方法</td></tr>
<tr><td style="text-align: left"></td><td style="text-align: left">CONFIG_BPF_STREAM_PARSER</td><td style="text-align: left">启用此功能允许使用BPF_MAP_TYPE_SOCKMAP与TCP流解析器配合使用</td></tr>
<tr><td style="text-align: left"></td><td style="text-align: left">CONFIG_LWTUNNEL_BPF</td><td style="text-align: left">在路由查找入站和出站数据包后允许作为下一跳操作运行BPF程序</td></tr>
<tr><td style="text-align: left"></td><td style="text-align: left">CONFIG_NETFILTER_XT_MATCH_BPF</td><td style="text-align: left">BPF匹配将对每个数据包应用Linux套接字过滤器并接受过滤器返回非零值的数据包</td></tr>
<tr><td style="text-align: left"></td><td style="text-align: left">CONFIG_IPV6_SEG6_BPF</td><td style="text-align: left">为支持BPF seg6local挂钩添加IPv6 Segement Routing助手 <a href="https://github.com/torvalds/linux/commit/fe94cc290f535709d3c5ebd1e472dfd0aec7ee7">参考</a></td></tr>
<tr><td style="text-align: left"><strong>kprobes</strong></td><td style="text-align: left">CONFIG_KPROBE_EVENTS</td><td style="text-align: left">允许用户通过ftrace接口动态添加跟踪事件类似于tracepoints</td></tr>
<tr><td style="text-align: left"></td><td style="text-align: left">CONFIG_KPROBES</td><td style="text-align: left">启用基于kprobes的动态事件</td></tr>
<tr><td style="text-align: left"></td><td style="text-align: left">CONFIG_HAVE_KPROBES</td><td style="text-align: left">检查是否启用了kprobes</td></tr>
<tr><td style="text-align: left"></td><td style="text-align: left">CONFIG_HAVE_REGS_AND_STACK_ACCESS_API</td><td style="text-align: left">如果架构支持从pt_regs访问寄存器和堆栈条目所需的API则应该选择此符号。例如基于kprobes的事件跟踪器需要此API</td></tr>
<tr><td style="text-align: left"></td><td style="text-align: left">CONFIG_KPROBES_ON_FTRACE</td><td style="text-align: left">如果架构支持将pt_regs完全传递给函数跟踪则在函数跟踪器上有kprobes</td></tr>
<tr><td style="text-align: left"><strong>kprobe multi</strong></td><td style="text-align: left">CONFIG_FPROBE</td><td style="text-align: left">启用fprobe以一次性在多个函数上附加探测点</td></tr>
<tr><td style="text-align: left"><strong>kprobe override</strong></td><td style="text-align: left">CONFIG_BPF_KPROBE_OVERRIDE</td><td style="text-align: left">启用BPF程序覆盖kprobed函数</td></tr>
<tr><td style="text-align: left"><strong>uprobes</strong></td><td style="text-align: left">CONFIG_UPROBE_EVENTS</td><td style="text-align: left">启用基于uprobes的动态事件</td></tr>
<tr><td style="text-align: left"></td><td style="text-align: left">CONFIG_ARCH_SUPPORTS_UPROBES</td><td style="text-align: left">架构特定的uprobes支持</td></tr>
<tr><td style="text-align: left"></td><td style="text-align: left">CONFIG_UPROBES</td><td style="text-align: left">Uprobes是kprobes的用户空间对应项它们允许仪器应用程序如'perf probe')在用户空间二进制文件和库中建立非侵入性探测点,并在用户空间应用程序触发探测点时执行处理函数。</td></tr>
<tr><td style="text-align: left"><strong>Tracepoints</strong></td><td style="text-align: left">CONFIG_TRACEPOINTS</td><td style="text-align: left">启用在内核中插入Tracepoints并与问题函数连接</td></tr>
<tr><td style="text-align: left"></td><td style="text-align: left">CONFIG_HAVE_SYSCALL_TRACEPOINTS</td><td style="text-align: left">启用系统调用进入/退出跟踪</td></tr>
<tr><td style="text-align: left"><strong>Raw Tracepoints</strong></td><td style="text-align: left">Same as Tracepoints</td><td style="text-align: left"></td></tr>
<tr><td style="text-align: left"><strong>LSM</strong></td><td style="text-align: left">CONFIG_BPF_LSM</td><td style="text-align: left">使用BPF程序对安全钩子进行仪器化实现动态MAC和审计策略</td></tr>
<tr><td style="text-align: left"><strong>LIRC</strong></td><td style="text-align: left">CONFIG_BPF_LIRC_MODE2</td><td style="text-align: left">允许将BPF程序附加到lirc设备</td></tr>
</tbody></table>
</div>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../bcc-documents/kernel-versions.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../bcc-documents/reference_guide.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../bcc-documents/kernel-versions.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../bcc-documents/reference_guide.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script>
window.playground_copyable = true;
</script>
<script src="../elasticlunr.min.js"></script>
<script src="../mark.min.js"></script>
<script src="../searcher.js"></script>
<script src="../clipboard.min.js"></script>
<script src="../highlight.js"></script>
<script src="../book.js"></script>
<!-- Custom JS scripts -->
</div>
</body>
</html>