Add user guide

This commit is contained in:
2026-03-10 11:03:11 +01:00
parent 58d494e674
commit d28adcf52d
51 changed files with 10408 additions and 1 deletions

20
userGuide/README.md Normal file
View File

@@ -0,0 +1,20 @@
# Eden-sim - User Guide
## Introduction
This folder contains the user guide for the simulation library. The documentation can be accessed using a browser via book/index.html.
## Prerequisites
The user guide can be read without any prerequisites other than a browser to read the book/index.html
To build the book, a rust and mdbook installation is required. See [rust installation guide](https://rust-lang.github.io/rustup/installation/index.html) and [mdbook installation guide](https://rust-lang.github.io/mdBook/guide/installation.html).
## Usage
To build the book :
```console
mdbook build
```
To serve the book :
```console
mdbook serve --open
```

4
userGuide/book.toml Normal file
View File

@@ -0,0 +1,4 @@
[book]
title = "Eden-sim - User Guide"
authors = ["Quentin BAILLEUL"]
language = "en"

1
userGuide/book/.nojekyll Normal file
View File

@@ -0,0 +1 @@
This file makes sure that Github Pages doesn't process mdBook's output.

241
userGuide/book/404.html Normal file
View File

@@ -0,0 +1,241 @@
<!DOCTYPE HTML>
<html lang="en" class="light sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Page not found - Eden-sim - User Guide</title>
<base href="/">
<!-- 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-de23e50b.svg">
<link rel="shortcut icon" href="favicon-8114d1fc.png">
<link rel="stylesheet" href="css/variables-8adf115d.css">
<link rel="stylesheet" href="css/general-2459343d.css">
<link rel="stylesheet" href="css/chrome-ae938929.css">
<link rel="stylesheet" href="css/print-9e4910d8.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="fonts/fonts-9644e21d.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" id="mdbook-highlight-css" href="highlight-493f70e1.css">
<link rel="stylesheet" id="mdbook-tomorrow-night-css" href="tomorrow-night-4c0ae647.css">
<link rel="stylesheet" id="mdbook-ayu-highlight-css" href="ayu-highlight-3fdfc3ac.css">
<!-- Custom theme stylesheets -->
<!-- Provide site root and default themes to javascript -->
<script>
const path_to_root = "";
const default_light_theme = "light";
const default_dark_theme = "navy";
window.path_to_searchindex_js = "searchindex-43c2d326.js";
</script>
<!-- Start loading toc.js asap -->
<script src="toc-81bc4348.js"></script>
</head>
<body>
<div id="mdbook-help-container">
<div id="mdbook-help-popup">
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
<div>
<p>Press <kbd></kbd> or <kbd></kbd> to navigate between chapters</p>
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
<p>Press <kbd>?</kbd> to show this help</p>
<p>Press <kbd>Esc</kbd> to hide this help</p>
</div>
</div>
</div>
<div id="mdbook-body-container">
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
let theme = localStorage.getItem('mdbook-theme');
let 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>
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
let theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
const html = document.documentElement;
html.classList.remove('light')
html.classList.add(theme);
html.classList.add("js");
</script>
<input type="checkbox" id="mdbook-sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
let sidebar = null;
const sidebar_toggle = document.getElementById("mdbook-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 = false;
}
if (sidebar === 'visible') {
sidebar_toggle.checked = true;
} else {
html.classList.remove('sidebar-visible');
}
</script>
<nav id="mdbook-sidebar" class="sidebar" aria-label="Table of contents">
<!-- populated by js -->
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
<noscript>
<iframe class="sidebar-iframe-outer" src="toc.html"></iframe>
</noscript>
<div id="mdbook-sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<div id="mdbook-page-wrapper" class="page-wrapper">
<div class="page">
<div id="mdbook-menu-bar-hover-placeholder"></div>
<div id="mdbook-menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="mdbook-sidebar-toggle" class="icon-button" for="mdbook-sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="mdbook-sidebar">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M0 96C0 78.3 14.3 64 32 64H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H32C14.3 128 0 113.7 0 96zM0 256c0-17.7 14.3-32 32-32H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H32c-17.7 0-32-14.3-32-32zM448 416c0 17.7-14.3 32-32 32H32c-17.7 0-32-14.3-32-32s14.3-32 32-32H416c17.7 0 32 14.3 32 32z"/></svg></span>
</label>
<button id="mdbook-theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="mdbook-theme-list">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M371.3 367.1c27.3-3.9 51.9-19.4 67.2-42.9L600.2 74.1c12.6-19.5 9.4-45.3-7.6-61.2S549.7-4.4 531.1 9.6L294.4 187.2c-24 18-38.2 46.1-38.4 76.1L371.3 367.1zm-19.6 25.4l-116-104.4C175.9 290.3 128 339.6 128 400c0 3.9 .2 7.8 .6 11.6c1.8 17.5-10.2 36.4-27.8 36.4H96c-17.7 0-32 14.3-32 32s14.3 32 32 32H240c61.9 0 112-50.1 112-112c0-2.5-.1-5-.2-7.5z"/></svg></span>
</button>
<ul id="mdbook-theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-default_theme">Auto</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-ayu">Ayu</button></li>
</ul>
<button id="mdbook-search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="mdbook-searchbar">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352c79.5 0 144-64.5 144-144s-64.5-144-144-144S64 128.5 64 208s64.5 144 144 144z"/></svg></span>
</button>
</div>
<h1 class="menu-title">Eden-sim - User Guide</h1>
<div class="right-buttons">
<a href="print.html" title="Print this book" aria-label="Print this book">
<span class=fa-svg id="print-button"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M128 0C92.7 0 64 28.7 64 64v96h64V64H354.7L384 93.3V160h64V93.3c0-17-6.7-33.3-18.7-45.3L400 18.7C388 6.7 371.7 0 354.7 0H128zM384 352v32 64H128V384 368 352H384zm64 32h32c17.7 0 32-14.3 32-32V256c0-35.3-28.7-64-64-64H64c-35.3 0-64 28.7-64 64v96c0 17.7 14.3 32 32 32H64v64c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V384zm-16-88c-13.3 0-24-10.7-24-24s10.7-24 24-24s24 10.7 24 24s-10.7 24-24 24z"/></svg></span>
</a>
</div>
</div>
<div id="mdbook-search-wrapper" class="hidden">
<form id="mdbook-searchbar-outer" class="searchbar-outer">
<div class="search-wrapper">
<input type="search" id="mdbook-searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="mdbook-searchresults-outer" aria-describedby="searchresults-header">
<div class="spinner-wrapper">
<span class=fa-svg id="fa-spin"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M304 48c0-26.5-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48s48-21.5 48-48zm0 416c0-26.5-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48s48-21.5 48-48zM48 304c26.5 0 48-21.5 48-48s-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48zm464-48c0-26.5-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48s48-21.5 48-48zM142.9 437c18.7-18.7 18.7-49.1 0-67.9s-49.1-18.7-67.9 0s-18.7 49.1 0 67.9s49.1 18.7 67.9 0zm0-294.2c18.7-18.7 18.7-49.1 0-67.9S93.7 56.2 75 75s-18.7 49.1 0 67.9s49.1 18.7 67.9 0zM369.1 437c18.7 18.7 49.1 18.7 67.9 0s18.7-49.1 0-67.9s-49.1-18.7-67.9 0s-18.7 49.1 0 67.9z"/></svg></span>
</div>
</div>
</form>
<div id="mdbook-searchresults-outer" class="searchresults-outer hidden">
<div id="mdbook-searchresults-header" class="searchresults-header"></div>
<ul id="mdbook-searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('mdbook-sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('mdbook-sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#mdbook-sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="mdbook-content" class="content">
<main>
<h1 id="document-not-found-404"><a class="header" href="#document-not-found-404">Document not found (404)</a></h1>
<p>This URL is invalid, sorry. Please use the navigation bar or search to continue.</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
</nav>
</div>
<template id=fa-eye><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M288 32c-80.8 0-145.5 36.8-192.6 80.6C48.6 156 17.3 208 2.5 243.7c-3.3 7.9-3.3 16.7 0 24.6C17.3 304 48.6 356 95.4 399.4C142.5 443.2 207.2 480 288 480s145.5-36.8 192.6-80.6c46.8-43.5 78.1-95.4 93-131.1c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C433.5 68.8 368.8 32 288 32zM432 256c0 79.5-64.5 144-144 144s-144-64.5-144-144s64.5-144 144-144s144 64.5 144 144zM288 192c0 35.3-28.7 64-64 64c-11.5 0-22.3-3-31.6-8.4c-.2 2.8-.4 5.5-.4 8.4c0 53 43 96 96 96s96-43 96-96s-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6z"/></svg></span></template>
<template id=fa-eye-slash><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M38.8 5.1C28.4-3.1 13.3-1.2 5.1 9.2S-1.2 34.7 9.2 42.9l592 464c10.4 8.2 25.5 6.3 33.7-4.1s6.3-25.5-4.1-33.7L525.6 386.7c39.6-40.6 66.4-86.1 79.9-118.4c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C465.5 68.8 400.8 32 320 32c-68.2 0-125 26.3-169.3 60.8L38.8 5.1zM223.1 149.5C248.6 126.2 282.7 112 320 112c79.5 0 144 64.5 144 144c0 24.9-6.3 48.3-17.4 68.7L408 294.5c5.2-11.8 8-24.8 8-38.5c0-53-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6c0 10.2-2.4 19.8-6.6 28.3l-90.3-70.8zm223.1 298L373 389.9c-16.4 6.5-34.3 10.1-53 10.1c-79.5 0-144-64.5-144-144c0-6.9 .5-13.6 1.4-20.2L83.1 161.5C60.3 191.2 44 220.8 34.5 243.7c-3.3 7.9-3.3 16.7 0 24.6c14.9 35.7 46.2 87.7 93 131.1C174.5 443.2 239.2 480 320 480c47.8 0 89.9-12.9 126.2-32.5z"/></svg></span></template>
<template id=fa-copy><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M502.6 70.63l-61.25-61.25C435.4 3.371 427.2 0 418.7 0H255.1c-35.35 0-64 28.66-64 64l.0195 256C192 355.4 220.7 384 256 384h192c35.2 0 64-28.8 64-64V93.25C512 84.77 508.6 76.63 502.6 70.63zM464 320c0 8.836-7.164 16-16 16H255.1c-8.838 0-16-7.164-16-16L239.1 64.13c0-8.836 7.164-16 16-16h128L384 96c0 17.67 14.33 32 32 32h47.1V320zM272 448c0 8.836-7.164 16-16 16H63.1c-8.838 0-16-7.164-16-16L47.98 192.1c0-8.836 7.164-16 16-16H160V128H63.99c-35.35 0-64 28.65-64 64l.0098 256C.002 483.3 28.66 512 64 512h192c35.2 0 64-28.8 64-64v-32h-47.1L272 448z"/></svg></span></template>
<template id=fa-play><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M73 39c-14.8-9.1-33.4-9.4-48.5-.9S0 62.6 0 80V432c0 17.4 9.4 33.4 24.5 41.9s33.7 8.1 48.5-.9L361 297c14.3-8.7 23-24.2 23-41s-8.7-32.2-23-41L73 39z"/></svg></span></template>
<template id=fa-clock-rotate-left><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M75 75L41 41C25.9 25.9 0 36.6 0 57.9V168c0 13.3 10.7 24 24 24H134.1c21.4 0 32.1-25.9 17-41l-30.8-30.8C155 85.5 203 64 256 64c106 0 192 86 192 192s-86 192-192 192c-40.8 0-78.6-12.7-109.7-34.4c-14.5-10.1-34.4-6.6-44.6 7.9s-6.6 34.4 7.9 44.6C151.2 495 201.7 512 256 512c141.4 0 256-114.6 256-256S397.4 0 256 0C185.3 0 121.3 28.7 75 75zm181 53c-13.3 0-24 10.7-24 24V256c0 6.4 2.5 12.5 7 17l72 72c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-65-65V152c0-13.3-10.7-24-24-24z"/></svg></span></template>
<!-- Livereload script (if served using the cli tool) -->
<script>
const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
const wsAddress = wsProtocol + "//" + location.host + "/" + "__livereload";
const socket = new WebSocket(wsAddress);
socket.onmessage = function (event) {
if (event.data === "reload") {
socket.close();
location.reload();
}
};
window.onbeforeunload = function() {
socket.close();
}
</script>
<script>
window.playground_copyable = true;
</script>
<script src="elasticlunr-ef4e11c1.min.js"></script>
<script src="mark-09e88c2c.min.js"></script>
<script src="searcher-c2a407aa.js"></script>
<script src="clipboard-1626706a.min.js"></script>
<script src="highlight-abc7f01d.js"></script>
<script src="book-a0b12cfe.js"></script>
<!-- Custom JS scripts -->
</div>
</body>
</html>

View File

@@ -0,0 +1,77 @@
/*
Based off of the Ayu theme
Original by Dempfi (https://github.com/dempfi/ayu)
*/
.hljs {
display: block;
overflow-x: auto;
background: #191f26;
color: #e6e1cf;
}
.hljs-comment,
.hljs-quote {
color: #5c6773;
}
.hljs-variable,
.hljs-template-variable,
.hljs-attribute,
.hljs-attr,
.hljs-regexp,
.hljs-link,
.hljs-selector-id,
.hljs-selector-class {
color: #ff7733;
}
.hljs-number,
.hljs-meta,
.hljs-builtin-name,
.hljs-literal,
.hljs-type,
.hljs-params {
color: #ffee99;
}
.hljs-string,
.hljs-bullet {
color: #b8cc52;
}
.hljs-title,
.hljs-built_in,
.hljs-section {
color: #ffb454;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-symbol {
color: #ff7733;
}
.hljs-name {
color: #36a3d9;
}
.hljs-tag {
color: #00568d;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}
.hljs-addition {
color: #91b362;
}
.hljs-deletion {
color: #d96c75;
}

View File

@@ -0,0 +1,843 @@
'use strict';
/* global default_theme, default_dark_theme, default_light_theme, hljs, ClipboardJS */
// Fix back button cache problem
window.onunload = function() { };
// Global variable, shared between modules
function playground_text(playground, hidden = true) {
const code_block = playground.querySelector('code');
if (window.ace && code_block.classList.contains('editable')) {
const editor = window.ace.edit(code_block);
return editor.getValue();
} else if (hidden) {
return code_block.textContent;
} else {
return code_block.innerText;
}
}
(function codeSnippets() {
function fetch_with_timeout(url, options, timeout = 6000) {
return Promise.race([
fetch(url, options),
new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), timeout)),
]);
}
const playgrounds = Array.from(document.querySelectorAll('.playground'));
if (playgrounds.length > 0) {
fetch_with_timeout('https://play.rust-lang.org/meta/crates', {
headers: {
'Content-Type': 'application/json',
},
method: 'POST',
mode: 'cors',
})
.then(response => response.json())
.then(response => {
// get list of crates available in the rust playground
const playground_crates = response.crates.map(item => item['id']);
playgrounds.forEach(block => handle_crate_list_update(block, playground_crates));
});
}
function handle_crate_list_update(playground_block, playground_crates) {
// update the play buttons after receiving the response
update_play_button(playground_block, playground_crates);
// and install on change listener to dynamically update ACE editors
if (window.ace) {
const code_block = playground_block.querySelector('code');
if (code_block.classList.contains('editable')) {
const editor = window.ace.edit(code_block);
editor.addEventListener('change', () => {
update_play_button(playground_block, playground_crates);
});
// add Ctrl-Enter command to execute rust code
editor.commands.addCommand({
name: 'run',
bindKey: {
win: 'Ctrl-Enter',
mac: 'Ctrl-Enter',
},
exec: _editor => run_rust_code(playground_block),
});
}
}
}
// updates the visibility of play button based on `no_run` class and
// used crates vs ones available on https://play.rust-lang.org
function update_play_button(pre_block, playground_crates) {
const play_button = pre_block.querySelector('.play-button');
// skip if code is `no_run`
if (pre_block.querySelector('code').classList.contains('no_run')) {
play_button.classList.add('hidden');
return;
}
// get list of `extern crate`'s from snippet
const txt = playground_text(pre_block);
const re = /extern\s+crate\s+([a-zA-Z_0-9]+)\s*;/g;
const snippet_crates = [];
let item;
while (item = re.exec(txt)) {
snippet_crates.push(item[1]);
}
// check if all used crates are available on play.rust-lang.org
const all_available = snippet_crates.every(function(elem) {
return playground_crates.indexOf(elem) > -1;
});
if (all_available) {
play_button.classList.remove('hidden');
play_button.hidden = false;
} else {
play_button.classList.add('hidden');
}
}
function run_rust_code(code_block) {
let result_block = code_block.querySelector('.result');
if (!result_block) {
result_block = document.createElement('code');
result_block.className = 'result hljs language-bash';
code_block.append(result_block);
}
const text = playground_text(code_block);
const classes = code_block.querySelector('code').classList;
let edition = '2015';
classes.forEach(className => {
if (className.startsWith('edition')) {
edition = className.slice(7);
}
});
const params = {
version: 'stable',
optimize: '0',
code: text,
edition: edition,
};
if (text.indexOf('#![feature') !== -1) {
params.version = 'nightly';
}
result_block.innerText = 'Running...';
fetch_with_timeout('https://play.rust-lang.org/evaluate.json', {
headers: {
'Content-Type': 'application/json',
},
method: 'POST',
mode: 'cors',
body: JSON.stringify(params),
})
.then(response => response.json())
.then(response => {
if (response.result.trim() === '') {
result_block.innerText = 'No output';
result_block.classList.add('result-no-output');
} else {
result_block.innerText = response.result;
result_block.classList.remove('result-no-output');
}
})
.catch(error => result_block.innerText = 'Playground Communication: ' + error.message);
}
// Syntax highlighting Configuration
hljs.configure({
tabReplace: ' ', // 4 spaces
languages: [], // Languages used for auto-detection
});
const code_nodes = Array
.from(document.querySelectorAll('code'))
// Don't highlight `inline code` blocks in headers.
.filter(function(node) {
return !node.parentElement.classList.contains('header');
});
if (window.ace) {
// language-rust class needs to be removed for editable
// blocks or highlightjs will capture events
code_nodes
.filter(function(node) {
return node.classList.contains('editable');
})
.forEach(function(block) {
block.classList.remove('language-rust');
});
code_nodes
.filter(function(node) {
return !node.classList.contains('editable');
})
.forEach(function(block) {
hljs.highlightBlock(block);
});
} else {
code_nodes.forEach(function(block) {
hljs.highlightBlock(block);
});
}
// Adding the hljs class gives code blocks the color css
// even if highlighting doesn't apply
code_nodes.forEach(function(block) {
block.classList.add('hljs');
});
Array.from(document.querySelectorAll('code.hljs')).forEach(function(block) {
const lines = Array.from(block.querySelectorAll('.boring'));
// If no lines were hidden, return
if (!lines.length) {
return;
}
block.classList.add('hide-boring');
const buttons = document.createElement('div');
buttons.className = 'buttons';
buttons.innerHTML = '<button title="Show hidden lines" \
aria-label="Show hidden lines"></button>';
buttons.firstChild.innerHTML = document.getElementById('fa-eye').innerHTML;
// add expand button
const pre_block = block.parentNode;
pre_block.insertBefore(buttons, pre_block.firstChild);
buttons.firstChild.addEventListener('click', function(e) {
if (this.title === 'Show hidden lines') {
this.innerHTML = document.getElementById('fa-eye-slash').innerHTML;
this.title = 'Hide lines';
this.setAttribute('aria-label', e.target.title);
block.classList.remove('hide-boring');
} else if (this.title === 'Hide lines') {
this.innerHTML = document.getElementById('fa-eye').innerHTML;
this.title = 'Show hidden lines';
this.setAttribute('aria-label', e.target.title);
block.classList.add('hide-boring');
}
});
});
if (window.playground_copyable) {
Array.from(document.querySelectorAll('pre code')).forEach(function(block) {
const pre_block = block.parentNode;
if (!pre_block.classList.contains('playground')) {
let buttons = pre_block.querySelector('.buttons');
if (!buttons) {
buttons = document.createElement('div');
buttons.className = 'buttons';
pre_block.insertBefore(buttons, pre_block.firstChild);
}
const clipButton = document.createElement('button');
clipButton.className = 'clip-button';
clipButton.title = 'Copy to clipboard';
clipButton.setAttribute('aria-label', clipButton.title);
clipButton.innerHTML = '<i class="tooltiptext"></i>';
buttons.insertBefore(clipButton, buttons.firstChild);
}
});
}
// Process playground code blocks
Array.from(document.querySelectorAll('.playground')).forEach(function(pre_block) {
// Add play button
let buttons = pre_block.querySelector('.buttons');
if (!buttons) {
buttons = document.createElement('div');
buttons.className = 'buttons';
pre_block.insertBefore(buttons, pre_block.firstChild);
}
const runCodeButton = document.createElement('button');
runCodeButton.className = 'play-button';
runCodeButton.hidden = true;
runCodeButton.title = 'Run this code';
runCodeButton.setAttribute('aria-label', runCodeButton.title);
runCodeButton.innerHTML = document.getElementById('fa-play').innerHTML;
buttons.insertBefore(runCodeButton, buttons.firstChild);
runCodeButton.addEventListener('click', () => {
run_rust_code(pre_block);
});
if (window.playground_copyable) {
const copyCodeClipboardButton = document.createElement('button');
copyCodeClipboardButton.className = 'clip-button';
copyCodeClipboardButton.innerHTML = '<i class="tooltiptext"></i>';
copyCodeClipboardButton.title = 'Copy to clipboard';
copyCodeClipboardButton.setAttribute('aria-label', copyCodeClipboardButton.title);
buttons.insertBefore(copyCodeClipboardButton, buttons.firstChild);
}
const code_block = pre_block.querySelector('code');
if (window.ace && code_block.classList.contains('editable')) {
const undoChangesButton = document.createElement('button');
undoChangesButton.className = 'reset-button';
undoChangesButton.title = 'Undo changes';
undoChangesButton.setAttribute('aria-label', undoChangesButton.title);
undoChangesButton.innerHTML +=
document.getElementById('fa-clock-rotate-left').innerHTML;
buttons.insertBefore(undoChangesButton, buttons.firstChild);
undoChangesButton.addEventListener('click', function() {
const editor = window.ace.edit(code_block);
editor.setValue(editor.originalCode);
editor.clearSelection();
});
}
});
})();
(function themes() {
const html = document.querySelector('html');
const themeToggleButton = document.getElementById('mdbook-theme-toggle');
const themePopup = document.getElementById('mdbook-theme-list');
const themeColorMetaTag = document.querySelector('meta[name="theme-color"]');
const themeIds = [];
themePopup.querySelectorAll('button.theme').forEach(function(el) {
themeIds.push(el.id);
});
const stylesheets = {
ayuHighlight: document.querySelector('#mdbook-ayu-highlight-css'),
tomorrowNight: document.querySelector('#mdbook-tomorrow-night-css'),
highlight: document.querySelector('#mdbook-highlight-css'),
};
function showThemes() {
themePopup.style.display = 'block';
themeToggleButton.setAttribute('aria-expanded', true);
themePopup.querySelector('button#mdbook-theme-' + get_theme()).focus();
}
function updateThemeSelected() {
themePopup.querySelectorAll('.theme-selected').forEach(function(el) {
el.classList.remove('theme-selected');
});
const selected = get_saved_theme() ?? 'default_theme';
let element = themePopup.querySelector('button#mdbook-theme-' + selected);
if (element === null) {
// Fall back in case there is no "Default" item.
element = themePopup.querySelector('button#mdbook-theme-' + get_theme());
}
element.classList.add('theme-selected');
}
function hideThemes() {
themePopup.style.display = 'none';
themeToggleButton.setAttribute('aria-expanded', false);
themeToggleButton.focus();
}
function get_saved_theme() {
let theme = null;
try {
theme = localStorage.getItem('mdbook-theme');
} catch {
// ignore error.
}
return theme;
}
function delete_saved_theme() {
localStorage.removeItem('mdbook-theme');
}
function get_theme() {
const theme = get_saved_theme();
if (theme === null || theme === undefined || !themeIds.includes('mdbook-theme-' + theme)) {
if (typeof default_dark_theme === 'undefined') {
// A customized index.hbs might not define this, so fall back to
// old behavior of determining the default on page load.
return default_theme;
}
return window.matchMedia('(prefers-color-scheme: dark)').matches
? default_dark_theme
: default_light_theme;
} else {
return theme;
}
}
let previousTheme = default_theme;
function set_theme(theme, store = true) {
let ace_theme;
if (theme === 'coal' || theme === 'navy') {
stylesheets.ayuHighlight.disabled = true;
stylesheets.tomorrowNight.disabled = false;
stylesheets.highlight.disabled = true;
ace_theme = 'ace/theme/tomorrow_night';
} else if (theme === 'ayu') {
stylesheets.ayuHighlight.disabled = false;
stylesheets.tomorrowNight.disabled = true;
stylesheets.highlight.disabled = true;
ace_theme = 'ace/theme/tomorrow_night';
} else {
stylesheets.ayuHighlight.disabled = true;
stylesheets.tomorrowNight.disabled = true;
stylesheets.highlight.disabled = false;
ace_theme = 'ace/theme/dawn';
}
setTimeout(function() {
themeColorMetaTag.content = getComputedStyle(document.documentElement).backgroundColor;
}, 1);
if (window.ace && window.editors) {
window.editors.forEach(function(editor) {
editor.setTheme(ace_theme);
});
}
if (store) {
try {
localStorage.setItem('mdbook-theme', theme);
} catch {
// ignore error.
}
}
html.classList.remove(previousTheme);
html.classList.add(theme);
previousTheme = theme;
updateThemeSelected();
}
const query = window.matchMedia('(prefers-color-scheme: dark)');
query.onchange = function() {
set_theme(get_theme(), false);
};
// Set theme.
set_theme(get_theme(), false);
themeToggleButton.addEventListener('click', function() {
if (themePopup.style.display === 'block') {
hideThemes();
} else {
showThemes();
}
});
themePopup.addEventListener('click', function(e) {
let theme;
if (e.target.className === 'theme') {
theme = e.target.id;
} else if (e.target.parentElement.className === 'theme') {
theme = e.target.parentElement.id;
} else {
return;
}
theme = theme.replace(/^mdbook-theme-/, '');
if (theme === 'default_theme' || theme === null) {
delete_saved_theme();
set_theme(get_theme(), false);
} else {
set_theme(theme);
}
});
themePopup.addEventListener('focusout', function(e) {
// e.relatedTarget is null in Safari and Firefox on macOS (see workaround below)
if (!!e.relatedTarget &&
!themeToggleButton.contains(e.relatedTarget) &&
!themePopup.contains(e.relatedTarget)
) {
hideThemes();
}
});
// Should not be needed, but it works around an issue on macOS & iOS:
// https://github.com/rust-lang/mdBook/issues/628
document.addEventListener('click', function(e) {
if (themePopup.style.display === 'block' &&
!themeToggleButton.contains(e.target) &&
!themePopup.contains(e.target)
) {
hideThemes();
}
});
document.addEventListener('keydown', function(e) {
if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) {
return;
}
if (!themePopup.contains(e.target)) {
return;
}
let li;
switch (e.key) {
case 'Escape':
e.preventDefault();
hideThemes();
break;
case 'ArrowUp':
e.preventDefault();
li = document.activeElement.parentElement;
if (li && li.previousElementSibling) {
li.previousElementSibling.querySelector('button').focus();
}
break;
case 'ArrowDown':
e.preventDefault();
li = document.activeElement.parentElement;
if (li && li.nextElementSibling) {
li.nextElementSibling.querySelector('button').focus();
}
break;
case 'Home':
e.preventDefault();
themePopup.querySelector('li:first-child button').focus();
break;
case 'End':
e.preventDefault();
themePopup.querySelector('li:last-child button').focus();
break;
}
});
})();
(function sidebar() {
const sidebar = document.getElementById('mdbook-sidebar');
const sidebarLinks = document.querySelectorAll('#mdbook-sidebar a');
const sidebarToggleButton = document.getElementById('mdbook-sidebar-toggle');
const sidebarResizeHandle = document.getElementById('mdbook-sidebar-resize-handle');
const sidebarCheckbox = document.getElementById('mdbook-sidebar-toggle-anchor');
let firstContact = null;
/* Because we cannot change the `display` using only CSS after/before the transition, we
need JS to do it. We change the display to prevent the browsers search to find text inside
the collapsed sidebar. */
if (!document.documentElement.classList.contains('sidebar-visible')) {
sidebar.style.display = 'none';
}
sidebar.addEventListener('transitionend', () => {
/* We only change the display to "none" if we're collapsing the sidebar. */
if (!sidebarCheckbox.checked) {
sidebar.style.display = 'none';
}
});
sidebarToggleButton.addEventListener('click', () => {
/* To allow the sidebar expansion animation, we first need to put back the display. */
if (!sidebarCheckbox.checked) {
sidebar.style.display = '';
// Workaround for Safari skipping the animation when changing
// `display` and a transform in the same event loop. This forces a
// reflow after updating the display.
sidebar.offsetHeight;
}
});
function showSidebar() {
document.documentElement.classList.add('sidebar-visible');
Array.from(sidebarLinks).forEach(function(link) {
link.setAttribute('tabIndex', 0);
});
sidebarToggleButton.setAttribute('aria-expanded', true);
sidebar.setAttribute('aria-hidden', false);
try {
localStorage.setItem('mdbook-sidebar', 'visible');
} catch {
// Ignore error.
}
}
function hideSidebar() {
document.documentElement.classList.remove('sidebar-visible');
Array.from(sidebarLinks).forEach(function(link) {
link.setAttribute('tabIndex', -1);
});
sidebarToggleButton.setAttribute('aria-expanded', false);
sidebar.setAttribute('aria-hidden', true);
try {
localStorage.setItem('mdbook-sidebar', 'hidden');
} catch {
// Ignore error.
}
}
// Toggle sidebar
sidebarCheckbox.addEventListener('change', function sidebarToggle() {
if (sidebarCheckbox.checked) {
const current_width = parseInt(
document.documentElement.style.getPropertyValue('--sidebar-target-width'), 10);
if (current_width < 150) {
document.documentElement.style.setProperty('--sidebar-target-width', '150px');
}
showSidebar();
} else {
hideSidebar();
}
});
sidebarResizeHandle.addEventListener('mousedown', initResize, false);
function initResize() {
window.addEventListener('mousemove', resize, false);
window.addEventListener('mouseup', stopResize, false);
document.documentElement.classList.add('sidebar-resizing');
}
function resize(e) {
let pos = e.clientX - sidebar.offsetLeft;
if (pos < 20) {
hideSidebar();
} else {
if (!document.documentElement.classList.contains('sidebar-visible')) {
showSidebar();
}
pos = Math.min(pos, window.innerWidth - 100);
document.documentElement.style.setProperty('--sidebar-target-width', pos + 'px');
}
}
//on mouseup remove windows functions mousemove & mouseup
function stopResize() {
document.documentElement.classList.remove('sidebar-resizing');
window.removeEventListener('mousemove', resize, false);
window.removeEventListener('mouseup', stopResize, false);
}
document.addEventListener('touchstart', function(e) {
firstContact = {
x: e.touches[0].clientX,
time: Date.now(),
};
}, { passive: true });
document.addEventListener('touchmove', function(e) {
if (!firstContact) {
return;
}
const curX = e.touches[0].clientX;
const xDiff = curX - firstContact.x,
tDiff = Date.now() - firstContact.time;
if (tDiff < 250 && Math.abs(xDiff) >= 150) {
if (xDiff >= 0 && firstContact.x < Math.min(document.body.clientWidth * 0.25, 300)) {
showSidebar();
} else if (xDiff < 0 && curX < 300) {
hideSidebar();
}
firstContact = null;
}
}, { passive: true });
})();
(function chapterNavigation() {
document.addEventListener('keydown', function(e) {
if (e.altKey || e.ctrlKey || e.metaKey) {
return;
}
if (window.search && window.search.hasFocus()) {
return;
}
const html = document.querySelector('html');
function next() {
const nextButton = document.querySelector('.nav-chapters.next');
if (nextButton) {
window.location.href = nextButton.href;
}
}
function prev() {
const previousButton = document.querySelector('.nav-chapters.previous');
if (previousButton) {
window.location.href = previousButton.href;
}
}
function showHelp() {
const container = document.getElementById('mdbook-help-container');
const overlay = document.getElementById('mdbook-help-popup');
container.style.display = 'flex';
// Clicking outside the popup will dismiss it.
const mouseHandler = event => {
if (overlay.contains(event.target)) {
return;
}
if (event.button !== 0) {
return;
}
event.preventDefault();
event.stopPropagation();
document.removeEventListener('mousedown', mouseHandler);
hideHelp();
};
// Pressing esc will dismiss the popup.
const escapeKeyHandler = event => {
if (event.key === 'Escape') {
event.preventDefault();
event.stopPropagation();
document.removeEventListener('keydown', escapeKeyHandler, true);
hideHelp();
}
};
document.addEventListener('keydown', escapeKeyHandler, true);
document.getElementById('mdbook-help-container')
.addEventListener('mousedown', mouseHandler);
}
function hideHelp() {
document.getElementById('mdbook-help-container').style.display = 'none';
}
// Usually needs the Shift key to be pressed
switch (e.key) {
case '?':
e.preventDefault();
showHelp();
break;
}
// Rest of the keys are only active when the Shift key is not pressed
if (e.shiftKey) {
return;
}
switch (e.key) {
case 'ArrowRight':
e.preventDefault();
if (html.dir === 'rtl') {
prev();
} else {
next();
}
break;
case 'ArrowLeft':
e.preventDefault();
if (html.dir === 'rtl') {
next();
} else {
prev();
}
break;
}
});
})();
(function clipboard() {
const clipButtons = document.querySelectorAll('.clip-button');
function hideTooltip(elem) {
elem.firstChild.innerText = '';
elem.className = 'clip-button';
}
function showTooltip(elem, msg) {
elem.firstChild.innerText = msg;
elem.className = 'clip-button tooltipped';
}
const clipboardSnippets = new ClipboardJS('.clip-button', {
text: function(trigger) {
hideTooltip(trigger);
const playground = trigger.closest('pre');
return playground_text(playground, false);
},
});
Array.from(clipButtons).forEach(function(clipButton) {
clipButton.addEventListener('mouseout', function(e) {
hideTooltip(e.currentTarget);
});
});
clipboardSnippets.on('success', function(e) {
e.clearSelection();
showTooltip(e.trigger, 'Copied!');
});
clipboardSnippets.on('error', function(e) {
showTooltip(e.trigger, 'Clipboard error!');
});
})();
(function scrollToTop() {
const menuTitle = document.querySelector('.menu-title');
menuTitle.addEventListener('click', function() {
document.scrollingElement.scrollTo({ top: 0, behavior: 'smooth' });
});
})();
(function controllMenu() {
const menu = document.getElementById('mdbook-menu-bar');
(function controllPosition() {
let scrollTop = document.scrollingElement.scrollTop;
let prevScrollTop = scrollTop;
const minMenuY = -menu.clientHeight - 50;
// When the script loads, the page can be at any scroll (e.g. if you refresh it).
menu.style.top = scrollTop + 'px';
// Same as parseInt(menu.style.top.slice(0, -2), but faster
let topCache = menu.style.top.slice(0, -2);
menu.classList.remove('sticky');
let stickyCache = false; // Same as menu.classList.contains('sticky'), but faster
document.addEventListener('scroll', function() {
scrollTop = Math.max(document.scrollingElement.scrollTop, 0);
// `null` means that it doesn't need to be updated
let nextSticky = null;
let nextTop = null;
const scrollDown = scrollTop > prevScrollTop;
const menuPosAbsoluteY = topCache - scrollTop;
if (scrollDown) {
nextSticky = false;
if (menuPosAbsoluteY > 0) {
nextTop = prevScrollTop;
}
} else {
if (menuPosAbsoluteY > 0) {
nextSticky = true;
} else if (menuPosAbsoluteY < minMenuY) {
nextTop = prevScrollTop + minMenuY;
}
}
if (nextSticky === true && stickyCache === false) {
menu.classList.add('sticky');
stickyCache = true;
} else if (nextSticky === false && stickyCache === true) {
menu.classList.remove('sticky');
stickyCache = false;
}
if (nextTop !== null) {
menu.style.top = nextTop + 'px';
topCache = nextTop;
}
prevScrollTop = scrollTop;
}, { passive: true });
})();
(function controllBorder() {
function updateBorder() {
if (menu.offsetTop === 0) {
menu.classList.remove('bordered');
} else {
menu.classList.add('bordered');
}
}
updateBorder();
document.addEventListener('scroll', updateBorder, { passive: true });
})();
})();

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,756 @@
/* CSS for UI elements (a.k.a. chrome) */
html {
scrollbar-color: var(--scrollbar) transparent;
}
#mdbook-searchresults a,
.content a:link,
a:visited,
a > .hljs {
color: var(--links);
}
/*
mdbook-body-container is necessary because mobile browsers don't seem to like
overflow-x on the body tag when there is a <meta name="viewport"> tag.
*/
#mdbook-body-container {
/*
This is used when the sidebar pushes the body content off the side of
the screen on small screens. Without it, dragging on mobile Safari
will want to reposition the viewport in a weird way.
*/
overflow-x: clip;
}
/* Menu Bar */
#mdbook-menu-bar,
#mdbook-menu-bar-hover-placeholder {
z-index: 101;
margin: auto calc(0px - var(--page-padding));
}
#mdbook-menu-bar {
position: relative;
display: flex;
flex-wrap: wrap;
background-color: var(--bg);
border-block-end-color: var(--bg);
border-block-end-width: 1px;
border-block-end-style: solid;
}
#mdbook-menu-bar.sticky,
#mdbook-menu-bar-hover-placeholder:hover + #mdbook-menu-bar,
#mdbook-menu-bar:hover,
html.sidebar-visible #mdbook-menu-bar {
position: -webkit-sticky;
position: sticky;
top: 0 !important;
}
#mdbook-menu-bar-hover-placeholder {
position: sticky;
position: -webkit-sticky;
top: 0;
height: var(--menu-bar-height);
}
#mdbook-menu-bar.bordered {
border-block-end-color: var(--table-border-color);
}
#mdbook-menu-bar .fa-svg, #mdbook-menu-bar .icon-button {
position: relative;
padding: 0 8px;
z-index: 10;
line-height: var(--menu-bar-height);
cursor: pointer;
transition: color 0.5s;
}
@media only screen and (max-width: 420px) {
#mdbook-menu-bar .fa-svg, #mdbook-menu-bar .icon-button {
padding: 0 5px;
}
}
.icon-button {
border: none;
background: none;
padding: 0;
color: inherit;
}
.icon-button .fa-svg {
margin: 0;
}
.right-buttons {
margin: 0 15px;
}
.right-buttons a {
text-decoration: none;
}
.left-buttons {
display: flex;
margin: 0 5px;
}
html:not(.js) .left-buttons button {
display: none;
}
.menu-title {
display: inline-block;
font-weight: 200;
font-size: 2.4rem;
line-height: var(--menu-bar-height);
text-align: center;
margin: 0;
flex: 1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.menu-title {
cursor: pointer;
}
.menu-bar,
.menu-bar:visited,
.nav-chapters,
.nav-chapters:visited,
.mobile-nav-chapters,
.mobile-nav-chapters:visited,
.menu-bar .icon-button,
.menu-bar a .fa-svg {
color: var(--icons);
}
.menu-bar .fa-svg:hover,
.menu-bar .icon-button:hover,
.nav-chapters:hover,
.mobile-nav-chapters .fa-svg:hover {
color: var(--icons-hover);
}
/* Nav Icons */
.nav-chapters {
font-size: 2.5em;
text-align: center;
text-decoration: none;
position: fixed;
top: 0;
bottom: 0;
margin: 0;
max-width: 150px;
min-width: 90px;
display: flex;
justify-content: center;
align-content: center;
flex-direction: column;
transition: color 0.5s, background-color 0.5s;
}
.nav-chapters:hover {
text-decoration: none;
background-color: var(--theme-hover);
transition: background-color 0.15s, color 0.15s;
}
.nav-wrapper {
margin-block-start: 50px;
display: none;
}
.mobile-nav-chapters {
font-size: 2.5em;
text-align: center;
text-decoration: none;
width: 90px;
border-radius: 5px;
background-color: var(--sidebar-bg);
}
/* Only Firefox supports flow-relative values */
.previous { float: left; }
[dir=rtl] .previous { float: right; }
/* Only Firefox supports flow-relative values */
.next {
float: right;
right: var(--page-padding);
}
[dir=rtl] .next {
float: left;
right: unset;
left: var(--page-padding);
}
@media only screen and (max-width: 1080px) {
.nav-wide-wrapper { display: none; }
.nav-wrapper { display: block; }
}
/* sidebar-visible */
@media only screen and (max-width: 1380px) {
#mdbook-sidebar-toggle-anchor:checked ~ .page-wrapper .nav-wide-wrapper { display: none; }
#mdbook-sidebar-toggle-anchor:checked ~ .page-wrapper .nav-wrapper { display: block; }
}
/* Inline code */
:not(pre) > .hljs {
display: inline;
padding: 0.1em 0.3em;
border-radius: 3px;
}
:not(pre):not(a) > .hljs {
color: var(--inline-code-color);
overflow-x: initial;
}
a:hover > .hljs {
text-decoration: underline;
}
pre {
position: relative;
}
pre > .buttons {
position: absolute;
z-index: 100;
right: 0px;
top: 2px;
margin: 0px;
padding: 2px 0px;
color: var(--sidebar-fg);
cursor: pointer;
visibility: hidden;
opacity: 0;
transition: visibility 0.1s linear, opacity 0.1s linear;
}
pre:hover > .buttons {
visibility: visible;
opacity: 1
}
pre > .buttons :hover {
color: var(--sidebar-active);
border-color: var(--icons-hover);
background-color: var(--theme-hover);
}
pre > .buttons button {
cursor: inherit;
margin: 0px 5px;
padding: 2px 3px 0px 4px;
font-size: 23px;
border-style: solid;
border-width: 1px;
border-radius: 4px;
border-color: var(--icons);
background-color: var(--theme-popup-bg);
transition: 100ms;
transition-property: color,border-color,background-color;
color: var(--icons);
}
pre > .buttons button.clip-button {
padding: 2px 4px 0px 6px;
}
pre > .buttons button.clip-button::before {
/* clipboard image from octicons (https://github.com/primer/octicons/tree/v2.0.0) MIT license
*/
content: url('data:image/svg+xml,<svg width="21" height="20" viewBox="0 0 24 25" \
xmlns="http://www.w3.org/2000/svg" aria-label="Copy to clipboard">\
<path d="M18 20h2v3c0 1-1 2-2 2H2c-.998 0-2-1-2-2V5c0-.911.755-1.667 1.667-1.667h5A3.323 3.323 0 \
0110 0a3.323 3.323 0 013.333 3.333h5C19.245 3.333 20 4.09 20 5v8.333h-2V9H2v14h16v-3zM3 \
7h14c0-.911-.793-1.667-1.75-1.667H13.5c-.957 0-1.75-.755-1.75-1.666C11.75 2.755 10.957 2 10 \
2s-1.75.755-1.75 1.667c0 .911-.793 1.666-1.75 1.666H4.75C3.793 5.333 3 6.09 3 7z"/>\
<path d="M4 19h6v2H4zM12 11H4v2h8zM4 17h4v-2H4zM15 15v-3l-4.5 4.5L15 21v-3l8.027-.032L23 15z"/>\
</svg>');
filter: var(--copy-button-filter);
}
pre > .buttons button.clip-button:hover::before {
filter: var(--copy-button-filter-hover);
}
@media (pointer: coarse) {
pre > .buttons button {
/* On mobile, make it easier to tap buttons. */
padding: 0.3rem 1rem;
}
.sidebar-resize-indicator {
/* Hide resize indicator on devices with limited accuracy */
display: none;
}
}
pre > code {
display: block;
padding: 1rem;
}
/* FIXME: ACE editors overlap their buttons because ACE does absolute
positioning within the code block which breaks padding. The only solution I
can think of is to move the padding to the outer pre tag (or insert a div
wrapper), but that would require fixing a whole bunch of CSS rules.
*/
.hljs.ace_editor {
padding: 0rem 0rem;
}
pre > .result {
margin-block-start: 10px;
}
/* Search */
#mdbook-searchresults a {
text-decoration: none;
}
mark {
border-radius: 2px;
padding-block-start: 0;
padding-block-end: 1px;
padding-inline-start: 3px;
padding-inline-end: 3px;
margin-block-start: 0;
margin-block-end: -1px;
margin-inline-start: -3px;
margin-inline-end: -3px;
background-color: var(--search-mark-bg);
transition: background-color 300ms linear;
cursor: pointer;
}
mark.fade-out {
background-color: rgba(0,0,0,0) !important;
cursor: auto;
}
.searchbar-outer {
margin-inline-start: auto;
margin-inline-end: auto;
max-width: var(--content-max-width);
}
#mdbook-searchbar-outer.searching #mdbook-searchbar {
padding-right: 30px;
}
#mdbook-searchbar-outer .spinner-wrapper {
display: none;
}
#mdbook-searchbar-outer.searching .spinner-wrapper {
display: block;
}
.search-wrapper {
position: relative;
}
.spinner-wrapper {
--spinner-margin: 2px;
position: absolute;
margin-block-start: calc(var(--searchbar-margin-block-start) + var(--spinner-margin));
right: var(--spinner-margin);
top: 0;
bottom: var(--spinner-margin);
padding: 6px;
background-color: var(--bg);
}
#fa-spin {
animation: rotating 2s linear infinite;
display: inline-block;
}
@keyframes rotating {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
#mdbook-searchbar {
width: 100%;
margin-block-start: var(--searchbar-margin-block-start);
margin-block-end: 0;
margin-inline-start: auto;
margin-inline-end: auto;
padding: 10px 16px;
transition: box-shadow 300ms ease-in-out;
border: 1px solid var(--searchbar-border-color);
border-radius: 3px;
background-color: var(--searchbar-bg);
color: var(--searchbar-fg);
}
#mdbook-searchbar:focus,
#mdbook-searchbar.active {
box-shadow: 0 0 3px var(--searchbar-shadow-color);
}
.searchresults-header {
font-weight: bold;
font-size: 1em;
padding-block-start: 18px;
padding-block-end: 0;
padding-inline-start: 5px;
padding-inline-end: 0;
color: var(--searchresults-header-fg);
}
.searchresults-outer {
margin-inline-start: auto;
margin-inline-end: auto;
max-width: var(--content-max-width);
border-block-end: 1px dashed var(--searchresults-border-color);
}
ul#mdbook-searchresults {
list-style: none;
padding-inline-start: 20px;
}
ul#mdbook-searchresults li {
margin: 10px 0px;
padding: 2px;
border-radius: 2px;
}
ul#mdbook-searchresults li.focus {
background-color: var(--searchresults-li-bg);
}
ul#mdbook-searchresults span.teaser {
display: block;
clear: both;
margin-block-start: 5px;
margin-block-end: 0;
margin-inline-start: 20px;
margin-inline-end: 0;
font-size: 0.8em;
}
ul#mdbook-searchresults span.teaser em {
font-weight: bold;
font-style: normal;
}
/* Sidebar */
.sidebar {
position: fixed;
left: 0;
top: 0;
bottom: 0;
width: var(--sidebar-width);
font-size: 0.875em;
box-sizing: border-box;
-webkit-overflow-scrolling: touch;
overscroll-behavior-y: contain;
background-color: var(--sidebar-bg);
color: var(--sidebar-fg);
}
.sidebar-iframe-inner {
--padding: 10px;
background-color: var(--sidebar-bg);
padding: var(--padding);
margin: 0;
font-size: 1.4rem;
color: var(--sidebar-fg);
min-height: calc(100vh - var(--padding) * 2);
}
.sidebar-iframe-outer {
border: none;
height: 100%;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
[dir=rtl] .sidebar { left: unset; right: 0; }
.sidebar-resizing {
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
}
html:not(.sidebar-resizing) .sidebar {
transition: transform 0.3s; /* Animation: slide away */
}
.sidebar code {
line-height: 2em;
}
.sidebar .sidebar-scrollbox {
overflow-y: auto;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
padding: 10px 10px;
}
.sidebar .sidebar-resize-handle {
position: absolute;
cursor: col-resize;
width: 0;
right: calc(var(--sidebar-resize-indicator-width) * -1);
top: 0;
bottom: 0;
display: flex;
align-items: center;
}
.sidebar-resize-handle .sidebar-resize-indicator {
width: 100%;
height: 16px;
color: var(--icons);
margin-inline-start: var(--sidebar-resize-indicator-space);
display: flex;
align-items: center;
justify-content: flex-start;
}
.sidebar-resize-handle .sidebar-resize-indicator::before {
content: "";
width: 2px;
height: 12px;
border-left: dotted 2px currentColor;
}
.sidebar-resize-handle .sidebar-resize-indicator::after {
content: "";
width: 2px;
height: 16px;
border-left: dotted 2px currentColor;
}
[dir=rtl] .sidebar .sidebar-resize-handle {
left: calc(var(--sidebar-resize-indicator-width) * -1);
right: unset;
}
.js .sidebar .sidebar-resize-handle {
cursor: col-resize;
width: calc(var(--sidebar-resize-indicator-width) - var(--sidebar-resize-indicator-space));
}
html:not(.js) .sidebar-resize-handle {
display: none;
}
/* sidebar-hidden */
#mdbook-sidebar-toggle-anchor:not(:checked) ~ .sidebar {
transform: translateX(calc(0px - var(--sidebar-width) - var(--sidebar-resize-indicator-width)));
}
[dir=rtl] #mdbook-sidebar-toggle-anchor:not(:checked) ~ .sidebar {
transform: translateX(calc(var(--sidebar-width) + var(--sidebar-resize-indicator-width)));
}
.sidebar::-webkit-scrollbar {
background: var(--sidebar-bg);
}
.sidebar::-webkit-scrollbar-thumb {
background: var(--scrollbar);
}
/* sidebar-visible */
#mdbook-sidebar-toggle-anchor:checked ~ .page-wrapper {
transform: translateX(calc(var(--sidebar-width) + var(--sidebar-resize-indicator-width)));
}
[dir=rtl] #mdbook-sidebar-toggle-anchor:checked ~ .page-wrapper {
transform: translateX(calc(0px - var(--sidebar-width) - var(--sidebar-resize-indicator-width)));
}
@media only screen and (min-width: 620px) {
#mdbook-sidebar-toggle-anchor:checked ~ .page-wrapper {
transform: none;
margin-inline-start: calc(var(--sidebar-width) + var(--sidebar-resize-indicator-width));
}
[dir=rtl] #mdbook-sidebar-toggle-anchor:checked ~ .page-wrapper {
transform: none;
}
}
.chapter {
list-style: none outside none;
padding-inline-start: 0;
line-height: 2.2em;
}
.chapter li {
color: var(--sidebar-non-existant);
}
/* This is a span wrapping the chapter link and the fold chevron. */
.chapter-link-wrapper {
/* Used to position the chevron to the right, allowing the text to wrap before it. */
display: flex;
}
.chapter li a {
/* Remove underlines. */
text-decoration: none;
color: var(--sidebar-fg);
}
.chapter li a:hover {
color: var(--sidebar-active);
}
.chapter li a.active {
color: var(--sidebar-active);
}
/* This is the toggle chevron. */
.chapter-fold-toggle {
cursor: pointer;
/* Positions the chevron to the side. */
margin-inline-start: auto;
padding: 0 10px;
user-select: none;
opacity: 0.68;
}
.chapter-fold-toggle div {
transition: transform 0.5s;
}
/* collapse the section */
.chapter li:not(.expanded) > ol {
display: none;
}
.chapter li.chapter-item {
line-height: 1.5em;
margin-block-start: 0.6em;
}
/* When expanded, rotate the chevron to point down. */
.chapter li.expanded > span > .chapter-fold-toggle div {
transform: rotate(90deg);
}
.chapter a.current-header {
color: var(--sidebar-active);
}
.on-this-page {
margin-left: 22px;
border-inline-start: 4px solid var(--sidebar-header-border-color);
padding-left: 8px;
}
.on-this-page > ol {
padding-left: 0;
}
/* Horizontal line in chapter list. */
.spacer {
width: 100%;
height: 3px;
margin: 5px 0px;
}
.chapter .spacer {
background-color: var(--sidebar-spacer);
}
/* On touch devices, add more vertical spacing to make it easier to tap links. */
@media (-moz-touch-enabled: 1), (pointer: coarse) {
.chapter li a { padding: 5px 0; }
.spacer { margin: 10px 0; }
}
.section {
list-style: none outside none;
padding-inline-start: 20px;
line-height: 1.9em;
}
/* Theme Menu Popup */
.theme-popup {
position: absolute;
left: 10px;
top: var(--menu-bar-height);
z-index: 1000;
border-radius: 4px;
font-size: 0.7em;
color: var(--fg);
background: var(--theme-popup-bg);
border: 1px solid var(--theme-popup-border);
margin: 0;
padding: 0;
list-style: none;
display: none;
/* Don't let the children's background extend past the rounded corners. */
overflow: hidden;
}
[dir=rtl] .theme-popup { left: unset; right: 10px; }
.theme-popup .default {
color: var(--icons);
}
.theme-popup .theme {
width: 100%;
border: 0;
margin: 0;
padding: 2px 20px;
line-height: 25px;
white-space: nowrap;
text-align: start;
cursor: pointer;
color: inherit;
background: inherit;
font-size: inherit;
}
.theme-popup .theme:hover {
background-color: var(--theme-hover);
}
.theme-selected::before {
display: inline-block;
content: "✓";
margin-inline-start: -14px;
width: 14px;
}
/* The container for the help popup that covers the whole window. */
#mdbook-help-container {
/* Position and size for the whole window. */
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
/* This uses flex layout (which is set in book.js), and centers the popup
in the window.*/
display: none;
align-items: center;
justify-content: center;
z-index: 1000;
/* Dim out the book while the popup is visible. */
background: var(--overlay-bg);
}
/* The popup help box. */
#mdbook-help-popup {
box-shadow: 0 4px 24px rgba(0,0,0,0.15);
min-width: 300px;
max-width: 500px;
width: 100%;
box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: center;
background-color: var(--bg);
color: var(--fg);
border-width: 1px;
border-color: var(--theme-popup-border);
border-style: solid;
border-radius: 8px;
padding: 10px;
}
.mdbook-help-title {
text-align: center;
/* mdbook's margin for h2 is way too large. */
margin: 10px;
}

View File

@@ -0,0 +1,408 @@
/* Base styles and content styles */
:root {
/* Browser default font-size is 16px, this way 1 rem = 10px */
font-size: 62.5%;
color-scheme: var(--color-scheme);
}
html {
font-family: "Open Sans", sans-serif;
color: var(--fg);
background-color: var(--bg);
text-size-adjust: none;
-webkit-text-size-adjust: none;
}
body {
margin: 0;
font-size: 1.6rem;
overflow-x: hidden;
}
code {
font-family: var(--mono-font) !important;
font-size: var(--code-font-size);
direction: ltr !important;
}
/* make long words/inline code not x overflow */
main {
overflow-wrap: break-word;
}
/* make wide tables scroll if they overflow */
.table-wrapper {
overflow-x: auto;
}
/* Don't change font size in headers. */
h1 code, h2 code, h3 code, h4 code, h5 code, h6 code {
font-size: unset;
}
.left { float: left; }
.right { float: right; }
.boring { opacity: 0.6; }
.hide-boring .boring { display: none; }
.hidden { display: none !important; }
h2, h3 { margin-block-start: 2.5em; }
h4, h5 { margin-block-start: 2em; }
.header + .header h3,
.header + .header h4,
.header + .header h5 {
margin-block-start: 1em;
}
h1:target::before,
h2:target::before,
h3:target::before,
h4:target::before,
h5:target::before,
h6:target::before,
dt:target::before {
display: inline-block;
content: "»";
margin-inline-start: -30px;
width: 30px;
}
/* This is broken on Safari as of version 14, but is fixed
in Safari Technology Preview 117 which I think will be Safari 14.2.
https://bugs.webkit.org/show_bug.cgi?id=218076
*/
:target {
/* Safari does not support logical properties */
scroll-margin-top: calc(var(--menu-bar-height) + 0.5em);
}
.page {
outline: 0;
padding: 0 var(--page-padding);
margin-block-start: calc(0px - var(--menu-bar-height)); /* Compensate for the #mdbook-menu-bar-hover-placeholder */
}
.page-wrapper {
box-sizing: border-box;
background-color: var(--bg);
}
html:not(.js) .page-wrapper,
.js:not(.sidebar-resizing) .page-wrapper {
transition: margin-left 0.3s ease, transform 0.3s ease; /* Animation: slide away */
}
[dir=rtl]:not(.js) .page-wrapper,
[dir=rtl].js:not(.sidebar-resizing) .page-wrapper {
transition: margin-right 0.3s ease, transform 0.3s ease; /* Animation: slide away */
}
.content {
overflow-y: auto;
padding: 0 5px 50px 5px;
}
.content main {
margin-inline-start: auto;
margin-inline-end: auto;
max-width: var(--content-max-width);
}
.content p { line-height: 1.45em; }
.content ol { line-height: 1.45em; }
.content ul { line-height: 1.45em; }
.content a { text-decoration: none; }
.content a:hover { text-decoration: underline; }
.content img, .content video { max-width: 100%; }
.content .header:link,
.content .header:visited {
color: var(--fg);
}
.content .header:link,
.content .header:visited:hover {
text-decoration: none;
}
table {
margin: 0 auto;
border-collapse: collapse;
}
table td {
padding: 3px 20px;
border: 1px var(--table-border-color) solid;
}
table thead {
background: var(--table-header-bg);
}
table thead td {
font-weight: 700;
border: none;
}
table thead th {
padding: 3px 20px;
}
table thead tr {
border: 1px var(--table-header-bg) solid;
}
/* Alternate background colors for rows */
table tbody tr:nth-child(2n) {
background: var(--table-alternate-bg);
}
blockquote {
margin: 20px 0;
padding: 0 20px;
color: var(--fg);
background-color: var(--quote-bg);
border-block-start: .1em solid var(--quote-border);
border-block-end: .1em solid var(--quote-border);
}
/* TODO: Remove .warning in a future version of mdbook, it is replaced by
blockquote tags. */
.warning {
margin: 20px;
padding: 0 20px;
border-inline-start: 2px solid var(--warning-border);
}
.warning:before {
position: absolute;
width: 3rem;
height: 3rem;
margin-inline-start: calc(-1.5rem - 21px);
content: "ⓘ";
text-align: center;
background-color: var(--bg);
color: var(--warning-border);
font-weight: bold;
font-size: 2rem;
}
blockquote .warning:before {
background-color: var(--quote-bg);
}
kbd {
background-color: var(--table-border-color);
border-radius: 4px;
border: solid 1px var(--theme-popup-border);
box-shadow: inset 0 -1px 0 var(--theme-hover);
display: inline-block;
font-size: var(--code-font-size);
font-family: var(--mono-font);
line-height: 10px;
padding: 4px 5px;
vertical-align: middle;
}
sup {
/* Set the line-height for superscript and footnote references so that there
isn't an awkward space appearing above lines that contain the footnote.
See https://github.com/rust-lang/mdBook/pull/2443#discussion_r1813773583
for an explanation.
*/
line-height: 0;
}
.footnote-definition {
font-size: 0.9em;
}
/* The default spacing for a list is a little too large. */
.footnote-definition ul,
.footnote-definition ol {
padding-left: 20px;
}
.footnote-definition > li {
/* Required to position the ::before target */
position: relative;
}
.footnote-definition > li:target {
scroll-margin-top: 50vh;
}
.footnote-reference:target {
scroll-margin-top: 50vh;
}
/* Draws a border around the footnote (including the marker) when it is selected.
TODO: If there are multiple linkbacks, highlight which one you just came
from so you know which one to click.
*/
.footnote-definition > li:target::before {
border: 2px solid var(--footnote-highlight);
border-radius: 6px;
position: absolute;
top: -8px;
right: -8px;
bottom: -8px;
left: -32px;
pointer-events: none;
content: "";
}
/* Pulses the footnote reference so you can quickly see where you left off reading.
This could use some improvement.
*/
@media not (prefers-reduced-motion) {
.footnote-reference:target {
animation: fn-highlight 0.8s;
border-radius: 2px;
}
@keyframes fn-highlight {
from {
background-color: var(--footnote-highlight);
}
}
}
.tooltiptext {
position: absolute;
visibility: hidden;
color: #fff;
background-color: #333;
transform: translateX(-50%); /* Center by moving tooltip 50% of its width left */
left: -8px; /* Half of the width of the icon */
top: -35px;
font-size: 0.8em;
text-align: center;
border-radius: 6px;
padding: 5px 8px;
margin: 5px;
z-index: 1000;
}
.tooltipped .tooltiptext {
visibility: visible;
}
.chapter li.part-title {
color: var(--sidebar-fg);
margin: 5px 0px;
font-weight: bold;
}
.result-no-output {
font-style: italic;
}
.fa-svg svg {
width: 1em;
height: 1em;
fill: currentColor;
margin-bottom: -0.1em;
}
dt {
font-weight: bold;
margin-top: 0.5em;
margin-bottom: 0.1em;
}
/* This uses a CSS counter to add numbers to definitions, but only if there is
more than one definition. */
dl, dt {
counter-reset: dd-counter;
}
/* When there is more than one definition, increment the counter. The first
selector selects the first definition, and the second one selects definitions
2 and beyond.*/
dd:has(+ dd), dd + dd {
counter-increment: dd-counter;
/* Use flex display to help with positioning the numbers when there is a p
tag inside the definition. */
display: flex;
align-items: flex-start;
}
/* Shows the counter for definitions. The first selector selects the first
definition, and the second one selections definitions 2 and beyond.*/
dd:has(+ dd)::before, dd + dd::before {
content: counter(dd-counter) ". ";
font-weight: 600;
display: inline-block;
margin-right: 0.5em;
}
dd > p {
/* For loose definitions that have a p tag inside, don't add a bunch of
space before the definition. */
margin-top: 0;
}
/* Remove some excess space from the bottom. */
.blockquote-tag p:last-child {
margin-bottom: 2px;
}
.blockquote-tag {
/* Add some padding to make the vertical bar a little taller than the text.*/
padding: 2px 0px 2px 20px;
/* Add a solid color bar on the left side. */
border-inline-start-style: solid;
border-inline-start-width: 4px;
/* Disable the background color from normal blockquotes . */
background-color: inherit;
/* Disable border blocks from blockquotes. */
border-block-start: none;
border-block-end: none;
}
.blockquote-tag-title svg {
fill: currentColor;
/* Add space between the icon and the title. */
margin-right: 8px;
}
.blockquote-tag-note {
border-inline-start-color: var(--blockquote-note-color);
}
.blockquote-tag-tip {
border-inline-start-color: var(--blockquote-tip-color);
}
.blockquote-tag-important {
border-inline-start-color: var(--blockquote-important-color);
}
.blockquote-tag-warning {
border-inline-start-color: var(--blockquote-warning-color);
}
.blockquote-tag-caution {
border-inline-start-color: var(--blockquote-caution-color);
}
.blockquote-tag-note .blockquote-tag-title {
color: var(--blockquote-note-color);
}
.blockquote-tag-tip .blockquote-tag-title {
color: var(--blockquote-tip-color);
}
.blockquote-tag-important .blockquote-tag-title {
color: var(--blockquote-important-color);
}
.blockquote-tag-warning .blockquote-tag-title {
color: var(--blockquote-warning-color);
}
.blockquote-tag-caution .blockquote-tag-title {
color: var(--blockquote-caution-color);
}
.blockquote-tag-title {
/* Slightly increase the weight for more emphasis. */
font-weight: 600;
/* Vertically center the icon with the text. */
display: flex;
align-items: center;
/* Remove default large margins for a more compact display. */
margin: 2px 0 8px 0;
}
.blockquote-tag-title .fa-svg {
fill: currentColor;
/* Add some space between the icon and the text. */
margin-right: 8px;
}

View File

@@ -0,0 +1,50 @@
#mdbook-sidebar,
#mdbook-menu-bar,
.nav-chapters,
.mobile-nav-chapters {
display: none;
}
#mdbook-page-wrapper.page-wrapper {
transform: none !important;
margin-inline-start: 0px;
overflow-y: initial;
}
#mdbook-content {
max-width: none;
margin: 0;
padding: 0;
}
.page {
overflow-y: initial;
}
code {
direction: ltr !important;
}
pre > .buttons {
z-index: 2;
}
a, a:visited, a:active, a:hover {
color: #4183c4;
text-decoration: none;
}
h1, h2, h3, h4, h5, h6 {
page-break-inside: avoid;
page-break-after: avoid;
}
pre, code {
page-break-inside: avoid;
white-space: pre-wrap;
}
.fa {
display: none !important;
}

View File

@@ -0,0 +1,383 @@
/* Globals */
:root {
--sidebar-target-width: 300px;
--sidebar-width: min(var(--sidebar-target-width), 80vw);
--sidebar-resize-indicator-width: 8px;
--sidebar-resize-indicator-space: 2px;
--page-padding: 15px;
--content-max-width: 750px;
--menu-bar-height: 50px;
--mono-font: "Source Code Pro", Consolas, "Ubuntu Mono", Menlo, "DejaVu Sans Mono", monospace, monospace;
--code-font-size: 0.875em; /* please adjust the ace font size accordingly in editor.js */
--searchbar-margin-block-start: 5px;
}
/* Themes */
.ayu {
--bg: hsl(210, 25%, 8%);
--fg: #c5c5c5;
--sidebar-bg: #14191f;
--sidebar-fg: #c8c9db;
--sidebar-non-existant: #5c6773;
--sidebar-active: #ffb454;
--sidebar-spacer: #2d334f;
--scrollbar: var(--sidebar-fg);
--icons: #737480;
--icons-hover: #b7b9cc;
--links: #0096cf;
--inline-code-color: #ffb454;
--theme-popup-bg: #14191f;
--theme-popup-border: #5c6773;
--theme-hover: #191f26;
--quote-bg: hsl(226, 15%, 17%);
--quote-border: hsl(226, 15%, 22%);
--warning-border: #ff8e00;
--table-border-color: hsl(210, 25%, 13%);
--table-header-bg: hsl(210, 25%, 28%);
--table-alternate-bg: hsl(210, 25%, 11%);
--searchbar-border-color: #848484;
--searchbar-bg: #424242;
--searchbar-fg: #fff;
--searchbar-shadow-color: #d4c89f;
--searchresults-header-fg: #666;
--searchresults-border-color: #888;
--searchresults-li-bg: #252932;
--search-mark-bg: #e3b171;
--color-scheme: dark;
/* Same as `--icons` */
--copy-button-filter: invert(45%) sepia(6%) saturate(621%) hue-rotate(198deg) brightness(99%) contrast(85%);
/* Same as `--sidebar-active` */
--copy-button-filter-hover: invert(68%) sepia(55%) saturate(531%) hue-rotate(341deg) brightness(104%) contrast(101%);
--footnote-highlight: #2668a6;
--overlay-bg: rgba(33, 40, 48, 0.4);
--blockquote-note-color: #74b9ff;
--blockquote-tip-color: #09ca09;
--blockquote-important-color: #d3abff;
--blockquote-warning-color: #f0b72f;
--blockquote-caution-color: #f21424;
--sidebar-header-border-color: #c18639;
}
.coal {
--bg: hsl(200, 7%, 8%);
--fg: #98a3ad;
--sidebar-bg: #292c2f;
--sidebar-fg: #a1adb8;
--sidebar-non-existant: #505254;
--sidebar-active: #3473ad;
--sidebar-spacer: #393939;
--scrollbar: var(--sidebar-fg);
--icons: #43484d;
--icons-hover: #b3c0cc;
--links: #2b79a2;
--inline-code-color: #c5c8c6;
--theme-popup-bg: #141617;
--theme-popup-border: #43484d;
--theme-hover: #1f2124;
--quote-bg: hsl(234, 21%, 18%);
--quote-border: hsl(234, 21%, 23%);
--warning-border: #ff8e00;
--table-border-color: hsl(200, 7%, 13%);
--table-header-bg: hsl(200, 7%, 28%);
--table-alternate-bg: hsl(200, 7%, 11%);
--searchbar-border-color: #aaa;
--searchbar-bg: #b7b7b7;
--searchbar-fg: #000;
--searchbar-shadow-color: #aaa;
--searchresults-header-fg: #666;
--searchresults-border-color: #98a3ad;
--searchresults-li-bg: #2b2b2f;
--search-mark-bg: #355c7d;
--color-scheme: dark;
/* Same as `--icons` */
--copy-button-filter: invert(26%) sepia(8%) saturate(575%) hue-rotate(169deg) brightness(87%) contrast(82%);
/* Same as `--sidebar-active` */
--copy-button-filter-hover: invert(36%) sepia(70%) saturate(503%) hue-rotate(167deg) brightness(98%) contrast(89%);
--footnote-highlight: #4079ae;
--overlay-bg: rgba(33, 40, 48, 0.4);
--blockquote-note-color: #4493f8;
--blockquote-tip-color: #08ae08;
--blockquote-important-color: #ab7df8;
--blockquote-warning-color: #d29922;
--blockquote-caution-color: #d91b29;
--sidebar-header-border-color: #3473ad;
}
.light, html:not(.js) {
--bg: hsl(0, 0%, 100%);
--fg: hsl(0, 0%, 0%);
--sidebar-bg: #fafafa;
--sidebar-fg: hsl(0, 0%, 0%);
--sidebar-non-existant: #aaaaaa;
--sidebar-active: #1f1fff;
--sidebar-spacer: #f4f4f4;
--scrollbar: #8F8F8F;
--icons: #747474;
--icons-hover: #000000;
--links: #20609f;
--inline-code-color: #301900;
--theme-popup-bg: #fafafa;
--theme-popup-border: #cccccc;
--theme-hover: #e6e6e6;
--quote-bg: hsl(197, 37%, 96%);
--quote-border: hsl(197, 37%, 91%);
--warning-border: #ff8e00;
--table-border-color: hsl(0, 0%, 95%);
--table-header-bg: hsl(0, 0%, 80%);
--table-alternate-bg: hsl(0, 0%, 97%);
--searchbar-border-color: #aaa;
--searchbar-bg: #fafafa;
--searchbar-fg: #000;
--searchbar-shadow-color: #aaa;
--searchresults-header-fg: #666;
--searchresults-border-color: #888;
--searchresults-li-bg: #e4f2fe;
--search-mark-bg: #a2cff5;
--color-scheme: light;
/* Same as `--icons` */
--copy-button-filter: invert(45.49%);
/* Same as `--sidebar-active` */
--copy-button-filter-hover: invert(14%) sepia(93%) saturate(4250%) hue-rotate(243deg) brightness(99%) contrast(130%);
--footnote-highlight: #7e7eff;
--overlay-bg: rgba(200, 200, 205, 0.4);
--blockquote-note-color: #0969da;
--blockquote-tip-color: #008000;
--blockquote-important-color: #8250df;
--blockquote-warning-color: #9a6700;
--blockquote-caution-color: #b52731;
--sidebar-header-border-color: #6e6edb;
}
.navy {
--bg: hsl(226, 23%, 11%);
--fg: #bcbdd0;
--sidebar-bg: #282d3f;
--sidebar-fg: #c8c9db;
--sidebar-non-existant: #505274;
--sidebar-active: #2b79a2;
--sidebar-spacer: #2d334f;
--scrollbar: var(--sidebar-fg);
--icons: #737480;
--icons-hover: #b7b9cc;
--links: #2b79a2;
--inline-code-color: #c5c8c6;
--theme-popup-bg: #161923;
--theme-popup-border: #737480;
--theme-hover: #282e40;
--quote-bg: hsl(226, 15%, 17%);
--quote-border: hsl(226, 15%, 22%);
--warning-border: #ff8e00;
--table-border-color: hsl(226, 23%, 16%);
--table-header-bg: hsl(226, 23%, 31%);
--table-alternate-bg: hsl(226, 23%, 14%);
--searchbar-border-color: #aaa;
--searchbar-bg: #aeaec6;
--searchbar-fg: #000;
--searchbar-shadow-color: #aaa;
--searchresults-header-fg: #5f5f71;
--searchresults-border-color: #5c5c68;
--searchresults-li-bg: #242430;
--search-mark-bg: #a2cff5;
--color-scheme: dark;
/* Same as `--icons` */
--copy-button-filter: invert(51%) sepia(10%) saturate(393%) hue-rotate(198deg) brightness(86%) contrast(87%);
/* Same as `--sidebar-active` */
--copy-button-filter-hover: invert(46%) sepia(20%) saturate(1537%) hue-rotate(156deg) brightness(85%) contrast(90%);
--footnote-highlight: #4079ae;
--overlay-bg: rgba(33, 40, 48, 0.4);
--blockquote-note-color: #4493f8;
--blockquote-tip-color: #09ca09;
--blockquote-important-color: #ab7df8;
--blockquote-warning-color: #d29922;
--blockquote-caution-color: #f21424;
--sidebar-header-border-color: #2f6ab5;
}
.rust {
--bg: hsl(60, 9%, 87%);
--fg: #262625;
--sidebar-bg: #3b2e2a;
--sidebar-fg: #c8c9db;
--sidebar-non-existant: #505254;
--sidebar-active: #e69f67;
--sidebar-spacer: #45373a;
--scrollbar: var(--sidebar-fg);
--icons: #737480;
--icons-hover: #262625;
--links: #2b79a2;
--inline-code-color: #6e6b5e;
--theme-popup-bg: #e1e1db;
--theme-popup-border: #b38f6b;
--theme-hover: #99908a;
--quote-bg: hsl(60, 5%, 75%);
--quote-border: hsl(60, 5%, 70%);
--warning-border: #ff8e00;
--table-border-color: hsl(60, 9%, 82%);
--table-header-bg: #b3a497;
--table-alternate-bg: hsl(60, 9%, 84%);
--searchbar-border-color: #aaa;
--searchbar-bg: #fafafa;
--searchbar-fg: #000;
--searchbar-shadow-color: #aaa;
--searchresults-header-fg: #666;
--searchresults-border-color: #888;
--searchresults-li-bg: #dec2a2;
--search-mark-bg: #e69f67;
/* Same as `--icons` */
--copy-button-filter: invert(51%) sepia(10%) saturate(393%) hue-rotate(198deg) brightness(86%) contrast(87%);
/* Same as `--sidebar-active` */
--copy-button-filter-hover: invert(77%) sepia(16%) saturate(1798%) hue-rotate(328deg) brightness(98%) contrast(83%);
--footnote-highlight: #d3a17a;
--overlay-bg: rgba(150, 150, 150, 0.25);
--blockquote-note-color: #023b95;
--blockquote-tip-color: #007700;
--blockquote-important-color: #8250df;
--blockquote-warning-color: #603700;
--blockquote-caution-color: #aa1721;
--sidebar-header-border-color: #8c391f;
}
@media (prefers-color-scheme: dark) {
html:not(.js) {
--bg: hsl(200, 7%, 8%);
--fg: #98a3ad;
--sidebar-bg: #292c2f;
--sidebar-fg: #a1adb8;
--sidebar-non-existant: #505254;
--sidebar-active: #3473ad;
--sidebar-spacer: #393939;
--scrollbar: var(--sidebar-fg);
--icons: #43484d;
--icons-hover: #b3c0cc;
--links: #2b79a2;
--inline-code-color: #c5c8c6;
--theme-popup-bg: #141617;
--theme-popup-border: #43484d;
--theme-hover: #1f2124;
--quote-bg: hsl(234, 21%, 18%);
--quote-border: hsl(234, 21%, 23%);
--warning-border: #ff8e00;
--table-border-color: hsl(200, 7%, 13%);
--table-header-bg: hsl(200, 7%, 28%);
--table-alternate-bg: hsl(200, 7%, 11%);
--searchbar-border-color: #aaa;
--searchbar-bg: #b7b7b7;
--searchbar-fg: #000;
--searchbar-shadow-color: #aaa;
--searchresults-header-fg: #666;
--searchresults-border-color: #98a3ad;
--searchresults-li-bg: #2b2b2f;
--search-mark-bg: #355c7d;
--color-scheme: dark;
/* Same as `--icons` */
--copy-button-filter: invert(26%) sepia(8%) saturate(575%) hue-rotate(169deg) brightness(87%) contrast(82%);
/* Same as `--sidebar-active` */
--copy-button-filter-hover: invert(36%) sepia(70%) saturate(503%) hue-rotate(167deg) brightness(98%) contrast(89%);
--footnote-highlight: #4079ae;
--overlay-bg: rgba(33, 40, 48, 0.4);
--blockquote-note-color: #4493f8;
--blockquote-tip-color: #08ae08;
--blockquote-important-color: #ab7df8;
--blockquote-warning-color: #d29922;
--blockquote-caution-color: #d91b29;
--sidebar-header-border-color: #3473ad;
}
}

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

@@ -0,0 +1,22 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 199.7 184.2">
<style>
@media (prefers-color-scheme: dark) {
svg { fill: white; }
}
</style>
<path d="M189.5,36.8c0.2,2.8,0,5.1-0.6,6.8L153,162c-0.6,2.1-2,3.7-4.2,5c-2.2,1.2-4.4,1.9-6.7,1.9H31.4c-9.6,0-15.3-2.8-17.3-8.4
c-0.8-2.2-0.8-3.9,0.1-5.2c0.9-1.2,2.4-1.8,4.6-1.8H123c7.4,0,12.6-1.4,15.4-4.1s5.7-8.9,8.6-18.4l32.9-108.6
c1.8-5.9,1-11.1-2.2-15.6S169.9,0,164,0H72.7c-1,0-3.1,0.4-6.1,1.1l0.1-0.4C64.5,0.2,62.6,0,61,0.1s-3,0.5-4.3,1.4
c-1.3,0.9-2.4,1.8-3.2,2.8S52,6.5,51.2,8.1c-0.8,1.6-1.4,3-1.9,4.3s-1.1,2.7-1.8,4.2c-0.7,1.5-1.3,2.7-2,3.7c-0.5,0.6-1.2,1.5-2,2.5
s-1.6,2-2.2,2.8s-0.9,1.5-1.1,2.2c-0.2,0.7-0.1,1.8,0.2,3.2c0.3,1.4,0.4,2.4,0.4,3.1c-0.3,3-1.4,6.9-3.3,11.6
c-1.9,4.7-3.6,8.1-5.1,10.1c-0.3,0.4-1.2,1.3-2.6,2.7c-1.4,1.4-2.3,2.6-2.6,3.7c-0.3,0.4-0.3,1.5-0.1,3.4c0.3,1.8,0.4,3.1,0.3,3.8
c-0.3,2.7-1.3,6.3-3,10.8c-1.7,4.5-3.4,8.2-5,11c-0.2,0.5-0.9,1.4-2,2.8c-1.1,1.4-1.8,2.5-2,3.4c-0.2,0.6-0.1,1.8,0.1,3.4
c0.2,1.6,0.2,2.8-0.1,3.6c-0.6,3-1.8,6.7-3.6,11c-1.8,4.3-3.6,7.9-5.4,11c-0.5,0.8-1.1,1.7-2,2.8c-0.8,1.1-1.5,2-2,2.8
s-0.8,1.6-1,2.5c-0.1,0.5,0,1.3,0.4,2.3c0.3,1.1,0.4,1.9,0.4,2.6c-0.1,1.1-0.2,2.6-0.5,4.4c-0.2,1.8-0.4,2.9-0.4,3.2
c-1.8,4.8-1.7,9.9,0.2,15.2c2.2,6.2,6.2,11.5,11.9,15.8c5.7,4.3,11.7,6.4,17.8,6.4h110.7c5.2,0,10.1-1.7,14.7-5.2s7.7-7.8,9.2-12.9
l33-108.6c1.8-5.8,1-10.9-2.2-15.5C194.9,39.7,192.6,38,189.5,36.8z M59.6,122.8L73.8,80c0,0,7,0,10.8,0s28.8-1.7,25.4,17.5
c-3.4,19.2-18.8,25.2-36.8,25.4S59.6,122.8,59.6,122.8z M78.6,116.8c4.7-0.1,18.9-2.9,22.1-17.1S89.2,86.3,89.2,86.3l-8.9,0
l-10.2,30.5C70.2,116.9,74,116.9,78.6,116.8z M75.3,68.7L89,26.2h9.8l0.8,34l23.6-34h9.9l-13.6,42.5h-7.1l12.5-35.4l-24.5,35.4h-6.8
l-0.8-35L82,68.7H75.3z"/>
</svg>
<!-- Original image Copyright Dave Gandy — CC BY 4.0 License -->

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -0,0 +1,93 @@
Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries.
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

View File

@@ -0,0 +1,100 @@
/* Open Sans is licensed under the Apache License, Version 2.0. See http://www.apache.org/licenses/LICENSE-2.0 */
/* Source Code Pro is under the Open Font License. See https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL */
/* open-sans-300 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 300;
src: local('Open Sans Light'), local('OpenSans-Light'),
url('../fonts/open-sans-v17-all-charsets-300-7736aa35.woff2') format('woff2');
}
/* open-sans-300italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: 300;
src: local('Open Sans Light Italic'), local('OpenSans-LightItalic'),
url('../fonts/open-sans-v17-all-charsets-300italic-2c7b95c0.woff2') format('woff2');
}
/* open-sans-regular - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 400;
src: local('Open Sans Regular'), local('OpenSans-Regular'),
url('../fonts/open-sans-v17-all-charsets-regular-2e3b1d34.woff2') format('woff2');
}
/* open-sans-italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: 400;
src: local('Open Sans Italic'), local('OpenSans-Italic'),
url('../fonts/open-sans-v17-all-charsets-italic-6c9463f7.woff2') format('woff2');
}
/* open-sans-600 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 600;
src: local('Open Sans SemiBold'), local('OpenSans-SemiBold'),
url('../fonts/open-sans-v17-all-charsets-600-486c6759.woff2') format('woff2');
}
/* open-sans-600italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: 600;
src: local('Open Sans SemiBold Italic'), local('OpenSans-SemiBoldItalic'),
url('../fonts/open-sans-v17-all-charsets-600italic-1a3e8659.woff2') format('woff2');
}
/* open-sans-700 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 700;
src: local('Open Sans Bold'), local('OpenSans-Bold'),
url('../fonts/open-sans-v17-all-charsets-700-c22fe8c7.woff2') format('woff2');
}
/* open-sans-700italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: 700;
src: local('Open Sans Bold Italic'), local('OpenSans-BoldItalic'),
url('../fonts/open-sans-v17-all-charsets-700italic-238ae959.woff2') format('woff2');
}
/* open-sans-800 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 800;
src: local('Open Sans ExtraBold'), local('OpenSans-ExtraBold'),
url('../fonts/open-sans-v17-all-charsets-800-3d2c812a.woff2') format('woff2');
}
/* open-sans-800italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: 800;
src: local('Open Sans ExtraBold Italic'), local('OpenSans-ExtraBoldItalic'),
url('../fonts/open-sans-v17-all-charsets-800italic-ba1521ec.woff2') format('woff2');
}
/* source-code-pro-500 - latin_vietnamese_latin-ext_greek_cyrillic-ext_cyrillic */
@font-face {
font-family: 'Source Code Pro';
font-style: normal;
font-weight: 500;
src: url('../fonts/source-code-pro-v11-all-charsets-500-2bdd9410.woff2') format('woff2');
}

View File

@@ -0,0 +1,535 @@
<!DOCTYPE HTML>
<html lang="en" class="light sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Network customization - Eden-sim - User Guide</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-de23e50b.svg">
<link rel="shortcut icon" href="../favicon-8114d1fc.png">
<link rel="stylesheet" href="../css/variables-8adf115d.css">
<link rel="stylesheet" href="../css/general-2459343d.css">
<link rel="stylesheet" href="../css/chrome-ae938929.css">
<link rel="stylesheet" href="../css/print-9e4910d8.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="../fonts/fonts-9644e21d.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" id="mdbook-highlight-css" href="../highlight-493f70e1.css">
<link rel="stylesheet" id="mdbook-tomorrow-night-css" href="../tomorrow-night-4c0ae647.css">
<link rel="stylesheet" id="mdbook-ayu-highlight-css" href="../ayu-highlight-3fdfc3ac.css">
<!-- Custom theme stylesheets -->
<!-- Provide site root and default themes to javascript -->
<script>
const path_to_root = "../";
const default_light_theme = "light";
const default_dark_theme = "navy";
window.path_to_searchindex_js = "../searchindex-43c2d326.js";
</script>
<!-- Start loading toc.js asap -->
<script src="../toc-81bc4348.js"></script>
</head>
<body>
<div id="mdbook-help-container">
<div id="mdbook-help-popup">
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
<div>
<p>Press <kbd></kbd> or <kbd></kbd> to navigate between chapters</p>
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
<p>Press <kbd>?</kbd> to show this help</p>
<p>Press <kbd>Esc</kbd> to hide this help</p>
</div>
</div>
</div>
<div id="mdbook-body-container">
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
let theme = localStorage.getItem('mdbook-theme');
let 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>
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
let theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
const html = document.documentElement;
html.classList.remove('light')
html.classList.add(theme);
html.classList.add("js");
</script>
<input type="checkbox" id="mdbook-sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
let sidebar = null;
const sidebar_toggle = document.getElementById("mdbook-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 = false;
}
if (sidebar === 'visible') {
sidebar_toggle.checked = true;
} else {
html.classList.remove('sidebar-visible');
}
</script>
<nav id="mdbook-sidebar" class="sidebar" aria-label="Table of contents">
<!-- populated by js -->
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
<noscript>
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
</noscript>
<div id="mdbook-sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<div id="mdbook-page-wrapper" class="page-wrapper">
<div class="page">
<div id="mdbook-menu-bar-hover-placeholder"></div>
<div id="mdbook-menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="mdbook-sidebar-toggle" class="icon-button" for="mdbook-sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="mdbook-sidebar">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M0 96C0 78.3 14.3 64 32 64H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H32C14.3 128 0 113.7 0 96zM0 256c0-17.7 14.3-32 32-32H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H32c-17.7 0-32-14.3-32-32zM448 416c0 17.7-14.3 32-32 32H32c-17.7 0-32-14.3-32-32s14.3-32 32-32H416c17.7 0 32 14.3 32 32z"/></svg></span>
</label>
<button id="mdbook-theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="mdbook-theme-list">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M371.3 367.1c27.3-3.9 51.9-19.4 67.2-42.9L600.2 74.1c12.6-19.5 9.4-45.3-7.6-61.2S549.7-4.4 531.1 9.6L294.4 187.2c-24 18-38.2 46.1-38.4 76.1L371.3 367.1zm-19.6 25.4l-116-104.4C175.9 290.3 128 339.6 128 400c0 3.9 .2 7.8 .6 11.6c1.8 17.5-10.2 36.4-27.8 36.4H96c-17.7 0-32 14.3-32 32s14.3 32 32 32H240c61.9 0 112-50.1 112-112c0-2.5-.1-5-.2-7.5z"/></svg></span>
</button>
<ul id="mdbook-theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-default_theme">Auto</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-ayu">Ayu</button></li>
</ul>
<button id="mdbook-search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="mdbook-searchbar">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352c79.5 0 144-64.5 144-144s-64.5-144-144-144S64 128.5 64 208s64.5 144 144 144z"/></svg></span>
</button>
</div>
<h1 class="menu-title">Eden-sim - User Guide</h1>
<div class="right-buttons">
<a href="../print.html" title="Print this book" aria-label="Print this book">
<span class=fa-svg id="print-button"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M128 0C92.7 0 64 28.7 64 64v96h64V64H354.7L384 93.3V160h64V93.3c0-17-6.7-33.3-18.7-45.3L400 18.7C388 6.7 371.7 0 354.7 0H128zM384 352v32 64H128V384 368 352H384zm64 32h32c17.7 0 32-14.3 32-32V256c0-35.3-28.7-64-64-64H64c-35.3 0-64 28.7-64 64v96c0 17.7 14.3 32 32 32H64v64c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V384zm-16-88c-13.3 0-24-10.7-24-24s10.7-24 24-24s24 10.7 24 24s-10.7 24-24 24z"/></svg></span>
</a>
</div>
</div>
<div id="mdbook-search-wrapper" class="hidden">
<form id="mdbook-searchbar-outer" class="searchbar-outer">
<div class="search-wrapper">
<input type="search" id="mdbook-searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="mdbook-searchresults-outer" aria-describedby="searchresults-header">
<div class="spinner-wrapper">
<span class=fa-svg id="fa-spin"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M304 48c0-26.5-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48s48-21.5 48-48zm0 416c0-26.5-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48s48-21.5 48-48zM48 304c26.5 0 48-21.5 48-48s-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48zm464-48c0-26.5-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48s48-21.5 48-48zM142.9 437c18.7-18.7 18.7-49.1 0-67.9s-49.1-18.7-67.9 0s-18.7 49.1 0 67.9s49.1 18.7 67.9 0zm0-294.2c18.7-18.7 18.7-49.1 0-67.9S93.7 56.2 75 75s-18.7 49.1 0 67.9s49.1 18.7 67.9 0zM369.1 437c18.7 18.7 49.1 18.7 67.9 0s18.7-49.1 0-67.9s-49.1-18.7-67.9 0s-18.7 49.1 0 67.9z"/></svg></span>
</div>
</div>
</form>
<div id="mdbook-searchresults-outer" class="searchresults-outer hidden">
<div id="mdbook-searchresults-header" class="searchresults-header"></div>
<ul id="mdbook-searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('mdbook-sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('mdbook-sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#mdbook-sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="mdbook-content" class="content">
<main>
<h1 id="network-customization"><a class="header" href="#network-customization">Network customization</a></h1>
<h2 id="introduction"><a class="header" href="#introduction">Introduction</a></h2>
<p>In the previous chapter, we wrote a simulation script for a simple Ethernet network. In this chapter, we will discuss how to customize it using the attributes of the different classes used.</p>
<h2 id="attributes-in-ns-3"><a class="header" href="#attributes-in-ns-3">Attributes in ns-3</a></h2>
<p>To organize access and configuration of instantiated object parameters, ns-3 uses its own attribute system.</p>
<p>In the previous chapter, we already implemented this overlay using the “SetAttribute()” function to configure the application. This function has two arguments. The first is a string corresponding to the name of the attribute to be changed. The second is the value to be assigned to this attribute.</p>
<p>The various attributes available for each object are visible in the C++ implementation of each object. Here is an example of the EthernetChannel object described in contrib/ethernet/model/ethernet-channel.cc.</p>
<pre><code class="language-c++">TypeId
EthernetChannel::GetTypeId()
{
static TypeId tid =
TypeId("ns3::EthernetChannel")
.SetParent&lt;Channel&gt;()
.SetGroupName("Ethernet")
.AddConstructor&lt;EthernetChannel&gt;()
.AddAttribute("Delay",
"Propagation delay through the channel",
TimeValue(NanoSeconds(25)),
MakeTimeAccessor(&amp;EthernetChannel::m_delay),
MakeTimeChecker())
.AddTraceSource("TxRxEthernet",
"Trace source indicating transmission of packet "
"from the EthernetChannel, used by the Animation "
"interface.",
MakeTraceSourceAccessor(&amp;EthernetChannel::m_txrxEthernet),
"ns3::EthernetChannel::TxRxAnimationCallback");
return tid;
}
</code></pre>
<p>We can see that this object has only one attribute called Delay, which allows you to configure the propagation delay. It is of type Time and has a default value of 25ns.</p>
<p>Thus, it is possible to configure the propagation delay in the previous simulation script as follows:</p>
<pre><code class="language-c++"> [...]
//Create Ethernet Channels and connect switch to the end-stations
Ptr&lt;EthernetChannel&gt; channel0 = CreateObject&lt;EthernetChannel&gt;();
channel0-&gt;SetAttribute("Delay", TimeValue(NanoSeconds(50)));
net0-&gt;Attach(channel0);
swnet0-&gt;Attach(channel0);
Ptr&lt;EthernetChannel&gt; channel1 = CreateObject&lt;EthernetChannel&gt;();
channel1-&gt;SetAttribute("Delay", TimeValue(NanoSeconds(75)));
net1-&gt;Attach(channel1);
swnet1-&gt;Attach(channel1);
Ptr&lt;EthernetChannel&gt; channel2 = CreateObject&lt;EthernetChannel&gt;();
channel2-&gt;SetAttribute("Delay", TimeValue(NanoSeconds(100)));
net2-&gt;Attach(channel2);
swnet2-&gt;Attach(channel2);
[...]
</code></pre>
<h2 id="common-attributes"><a class="header" href="#common-attributes">Common attributes</a></h2>
<p>Here are examples of the attributes most often used in Ethernet network simulations.</p>
<pre><code class="language-c++">[...]
//Create and add a netDevice to each end-station node
Ptr&lt;EthernetNetDevice&gt; net0 = CreateObject&lt;EthernetNetDevice&gt;();
net0-&gt;SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n0-&gt;AddDevice(net0);
Names::Add("ES1#01", net0);
Ptr&lt;EthernetNetDevice&gt; net1 = CreateObject&lt;EthernetNetDevice&gt;();
net1-&gt;SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n1-&gt;AddDevice(net1);
Names::Add("ES2#01", net1);
Ptr&lt;EthernetNetDevice&gt; net2 = CreateObject&lt;EthernetNetDevice&gt;();
net2-&gt;SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n2-&gt;AddDevice(net2);
Names::Add("ES3#01", net2);
//Create and add a netDevice to each switch port
Ptr&lt;EthernetNetDevice&gt; swnet0 = CreateObject&lt;EthernetNetDevice&gt;();
swnet0-&gt;SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n3-&gt;AddDevice(swnet0);
Names::Add("SW#01", swnet0);
Ptr&lt;EthernetNetDevice&gt; swnet1 = CreateObject&lt;EthernetNetDevice&gt;();
swnet1-&gt;SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n3-&gt;AddDevice(swnet1);
Names::Add("SW#02", swnet1);
Ptr&lt;EthernetNetDevice&gt; swnet2 = CreateObject&lt;EthernetNetDevice&gt;();
swnet2-&gt;SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n3-&gt;AddDevice(swnet2);
Names::Add("SW#03", swnet2);
[...]
//Create Ethernet Channels and connect switch to the end-stations
Ptr&lt;EthernetChannel&gt; channel0 = CreateObject&lt;EthernetChannel&gt;();
channel0-&gt;SetAttribute("Delay", TimeValue(NanoSeconds(50)));
net0-&gt;Attach(channel0);
swnet0-&gt;Attach(channel0);
Ptr&lt;EthernetChannel&gt; channel1 = CreateObject&lt;EthernetChannel&gt;();
channel1-&gt;SetAttribute("Delay", TimeValue(NanoSeconds(75)));
net1-&gt;Attach(channel1);
swnet1-&gt;Attach(channel1);
Ptr&lt;EthernetChannel&gt; channel2 = CreateObject&lt;EthernetChannel&gt;();
channel2-&gt;SetAttribute("Delay", TimeValue(NanoSeconds(100)));
net2-&gt;Attach(channel2);
swnet2-&gt;Attach(channel2);
[...]
//Create and add a switch net device to the switch node
Ptr&lt;SwitchNetDevice&gt; sw = CreateObject&lt;SwitchNetDevice&gt;();
sw-&gt;SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(2)));
sw-&gt;SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(5)));
n3-&gt;AddDevice(sw);
[...]
//Create 2 output port FIFOs for each netDevice.
for (int i=0; i&lt;2; i++){
Ptr&lt;DropTailQueue&lt;Packet&gt;&gt; q0 = CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;();
q0-&gt;SetAttribute("MaxSize", QueueSizeValue(QueueSize("250p")));
net0-&gt;SetQueue(q0);
[...]
//Application description
//ES1 -&gt; ES3 with priority 1
Ptr&lt;EthernetGenerator&gt; app0 = CreateObject&lt;EthernetGenerator&gt;();
app0-&gt;Setup(net0);
app0-&gt;SetAttribute("Address", AddressValue(net2-&gt;GetAddress()));
app0-&gt;SetAttribute("BurstSize", UintegerValue(2));
app0-&gt;SetAttribute("PayloadSize", UintegerValue(1400));
app0-&gt;SetAttribute("Period", TimeValue(Seconds(5)));
app0-&gt;SetAttribute("InterFrame", TimeValue(MilliSeconds(20)));
app0-&gt;SetAttribute("Jitter", TimeValue(MilliSeconds(50)));
app0-&gt;SetAttribute("Offset", TimeValue(Seconds(1)));
app0-&gt;SetAttribute("VlanID", UintegerValue(1));
app0-&gt;SetAttribute("PCP", UintegerValue(1));
app0-&gt;SetAttribute("DEI", UintegerValue(0));
[...]
</code></pre>
<h2 id="final-simulation-script"><a class="header" href="#final-simulation-script">Final simulation script</a></h2>
<p>Here is the simulation script you should have at the end of this chapter.</p>
<pre><code class="language-c++">#include "ns3/simulator.h"
#include "ns3/core-module.h"
#include "ns3/node.h"
#include "ns3/drop-tail-queue.h"
#include "ns3/ethernet-net-device.h"
#include "ns3/ethernet-channel.h"
#include "ns3/switch-net-device.h"
#include "ns3/ethernet-generator.h"
using namespace ns3;
NS_LOG_COMPONENT_DEFINE("Chapter 2");
//A callback to log the pkt emission
static void
MacTxCallback(std::string context, Ptr&lt;const Packet&gt; p)
{
NS_LOG_INFO((Simulator::Now()).As(Time::S) &lt;&lt; " \t" &lt;&lt; context &lt;&lt; " : Pkt #" &lt;&lt; p-&gt;GetUid() &lt;&lt; " sent!");
}
//A callback to log the pkt reception
static void
MacRxCallback(std::string context, Ptr&lt;const Packet&gt; p)
{
NS_LOG_INFO((Simulator::Now()).As(Time::S) &lt;&lt; " \t" &lt;&lt; context &lt;&lt; " : Pkt #" &lt;&lt; p-&gt;GetUid() &lt;&lt; " received!");
}
int
main(int argc, char* argv[])
{
//Enable logging
LogComponentEnable("Chapter 2", LOG_LEVEL_INFO);
//Create four nodes
Ptr&lt;Node&gt; n0 = CreateObject&lt;Node&gt;();
Names::Add("ES1", n0);
Ptr&lt;Node&gt; n1 = CreateObject&lt;Node&gt;();
Names::Add("ES2", n1);
Ptr&lt;Node&gt; n2 = CreateObject&lt;Node&gt;();
Names::Add("ES3", n2);
Ptr&lt;Node&gt; n3 = CreateObject&lt;Node&gt;();
Names::Add("SW", n3);
//Create and add a netDevice to each end-station node
Ptr&lt;EthernetNetDevice&gt; net0 = CreateObject&lt;EthernetNetDevice&gt;();
net0-&gt;SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n0-&gt;AddDevice(net0);
Names::Add("ES1#01", net0);
Ptr&lt;EthernetNetDevice&gt; net1 = CreateObject&lt;EthernetNetDevice&gt;();
net1-&gt;SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n1-&gt;AddDevice(net1);
Names::Add("ES2#01", net1);
Ptr&lt;EthernetNetDevice&gt; net2 = CreateObject&lt;EthernetNetDevice&gt;();
net2-&gt;SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n2-&gt;AddDevice(net2);
Names::Add("ES3#01", net2);
//Create and add a netDevice to each switch port
Ptr&lt;EthernetNetDevice&gt; swnet0 = CreateObject&lt;EthernetNetDevice&gt;();
swnet0-&gt;SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n3-&gt;AddDevice(swnet0);
Names::Add("SW#01", swnet0);
Ptr&lt;EthernetNetDevice&gt; swnet1 = CreateObject&lt;EthernetNetDevice&gt;();
swnet1-&gt;SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n3-&gt;AddDevice(swnet1);
Names::Add("SW#02", swnet1);
Ptr&lt;EthernetNetDevice&gt; swnet2 = CreateObject&lt;EthernetNetDevice&gt;();
swnet2-&gt;SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n3-&gt;AddDevice(swnet2);
Names::Add("SW#03", swnet2);
//Create Ethernet Channels and connect switch to the end-stations
Ptr&lt;EthernetChannel&gt; channel0 = CreateObject&lt;EthernetChannel&gt;();
channel0-&gt;SetAttribute("Delay", TimeValue(NanoSeconds(50)));
net0-&gt;Attach(channel0);
swnet0-&gt;Attach(channel0);
Ptr&lt;EthernetChannel&gt; channel1 = CreateObject&lt;EthernetChannel&gt;();
channel1-&gt;SetAttribute("Delay", TimeValue(NanoSeconds(75)));
net1-&gt;Attach(channel1);
swnet1-&gt;Attach(channel1);
Ptr&lt;EthernetChannel&gt; channel2 = CreateObject&lt;EthernetChannel&gt;();
channel2-&gt;SetAttribute("Delay", TimeValue(NanoSeconds(100)));
net2-&gt;Attach(channel2);
swnet2-&gt;Attach(channel2);
//Create and add a switch net device to the switch node
Ptr&lt;SwitchNetDevice&gt; sw = CreateObject&lt;SwitchNetDevice&gt;();
sw-&gt;SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(2)));
sw-&gt;SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(5)));
n3-&gt;AddDevice(sw);
sw-&gt;AddSwitchPort(swnet0);
sw-&gt;AddSwitchPort(swnet1);
sw-&gt;AddSwitchPort(swnet2);
//Allocate Mac addresses to the netDevices
net0-&gt;SetAddress(Mac48Address::Allocate());
net1-&gt;SetAddress(Mac48Address::Allocate());
net2-&gt;SetAddress(Mac48Address::Allocate());
sw-&gt;SetAddress(Mac48Address::Allocate());
//Create 2 output port FIFOs for each netDevice.
for (int i=0; i&lt;2; i++){
net0-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;());
net1-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;());
net2-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;());
swnet0-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;());
swnet1-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;());
swnet2-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;());
}
//Add a forwarding table entry
sw-&gt;AddForwardingTableEntry(Mac48Address::ConvertFrom(net2-&gt;GetAddress()), 1, {swnet2});
//Application description
//ES1 -&gt; ES3 with priority 1
Ptr&lt;EthernetGenerator&gt; app0 = CreateObject&lt;EthernetGenerator&gt;();
app0-&gt;Setup(net0);
app0-&gt;SetAttribute("Address", AddressValue(net2-&gt;GetAddress()));
app0-&gt;SetAttribute("BurstSize", UintegerValue(2));
app0-&gt;SetAttribute("PayloadSize", UintegerValue(1400));
app0-&gt;SetAttribute("Period", TimeValue(Seconds(5)));
app0-&gt;SetAttribute("InterFrame", TimeValue(MilliSeconds(20)));
app0-&gt;SetAttribute("Jitter", TimeValue(MilliSeconds(50)));
app0-&gt;SetAttribute("Offset", TimeValue(Seconds(1)));
app0-&gt;SetAttribute("VlanID", UintegerValue(1));
app0-&gt;SetAttribute("PCP", UintegerValue(1));
app0-&gt;SetAttribute("DEI", UintegerValue(0));
n0-&gt;AddApplication(app0);
app0-&gt;SetStartTime(Seconds(0));
app0-&gt;SetStopTime(Seconds(10));
//Callback declarations
//Callback to display the packet sent log
std::string context = Names::FindName(n0) + ":" + Names::FindName(net0);
net0-&gt;TraceConnectWithoutContext("MacTx", MakeBoundCallback(&amp;MacTxCallback, context));
//Callback to display the packet received log
context = Names::FindName(n2) + ":" + Names::FindName(net2);
net2-&gt;TraceConnectWithoutContext("MacRx", MakeBoundCallback(&amp;MacRxCallback, context));
//Execute the simulation
NS_LOG_INFO("Start of the simulation");
Simulator::Stop(Seconds(10));
Simulator::Run();
Simulator::Destroy();
NS_LOG_INFO("End of the simulation");
return 0;
}
</code></pre>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../getting_stated/simple_ethernet_network.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M41.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l160 160c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L109.3 256 246.6 118.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-160 160z"/></svg></span>
</a>
<a rel="next prefetch" href="../getting_stated/simple_tsn_network.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M278.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-160 160c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L210.7 256 73.4 118.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l160 160z"/></svg></span>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../getting_stated/simple_ethernet_network.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M41.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l160 160c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L109.3 256 246.6 118.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-160 160z"/></svg></span>
</a>
<a rel="next prefetch" href="../getting_stated/simple_tsn_network.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M278.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-160 160c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L210.7 256 73.4 118.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l160 160z"/></svg></span>
</a>
</nav>
</div>
<template id=fa-eye><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M288 32c-80.8 0-145.5 36.8-192.6 80.6C48.6 156 17.3 208 2.5 243.7c-3.3 7.9-3.3 16.7 0 24.6C17.3 304 48.6 356 95.4 399.4C142.5 443.2 207.2 480 288 480s145.5-36.8 192.6-80.6c46.8-43.5 78.1-95.4 93-131.1c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C433.5 68.8 368.8 32 288 32zM432 256c0 79.5-64.5 144-144 144s-144-64.5-144-144s64.5-144 144-144s144 64.5 144 144zM288 192c0 35.3-28.7 64-64 64c-11.5 0-22.3-3-31.6-8.4c-.2 2.8-.4 5.5-.4 8.4c0 53 43 96 96 96s96-43 96-96s-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6z"/></svg></span></template>
<template id=fa-eye-slash><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M38.8 5.1C28.4-3.1 13.3-1.2 5.1 9.2S-1.2 34.7 9.2 42.9l592 464c10.4 8.2 25.5 6.3 33.7-4.1s6.3-25.5-4.1-33.7L525.6 386.7c39.6-40.6 66.4-86.1 79.9-118.4c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C465.5 68.8 400.8 32 320 32c-68.2 0-125 26.3-169.3 60.8L38.8 5.1zM223.1 149.5C248.6 126.2 282.7 112 320 112c79.5 0 144 64.5 144 144c0 24.9-6.3 48.3-17.4 68.7L408 294.5c5.2-11.8 8-24.8 8-38.5c0-53-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6c0 10.2-2.4 19.8-6.6 28.3l-90.3-70.8zm223.1 298L373 389.9c-16.4 6.5-34.3 10.1-53 10.1c-79.5 0-144-64.5-144-144c0-6.9 .5-13.6 1.4-20.2L83.1 161.5C60.3 191.2 44 220.8 34.5 243.7c-3.3 7.9-3.3 16.7 0 24.6c14.9 35.7 46.2 87.7 93 131.1C174.5 443.2 239.2 480 320 480c47.8 0 89.9-12.9 126.2-32.5z"/></svg></span></template>
<template id=fa-copy><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M502.6 70.63l-61.25-61.25C435.4 3.371 427.2 0 418.7 0H255.1c-35.35 0-64 28.66-64 64l.0195 256C192 355.4 220.7 384 256 384h192c35.2 0 64-28.8 64-64V93.25C512 84.77 508.6 76.63 502.6 70.63zM464 320c0 8.836-7.164 16-16 16H255.1c-8.838 0-16-7.164-16-16L239.1 64.13c0-8.836 7.164-16 16-16h128L384 96c0 17.67 14.33 32 32 32h47.1V320zM272 448c0 8.836-7.164 16-16 16H63.1c-8.838 0-16-7.164-16-16L47.98 192.1c0-8.836 7.164-16 16-16H160V128H63.99c-35.35 0-64 28.65-64 64l.0098 256C.002 483.3 28.66 512 64 512h192c35.2 0 64-28.8 64-64v-32h-47.1L272 448z"/></svg></span></template>
<template id=fa-play><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M73 39c-14.8-9.1-33.4-9.4-48.5-.9S0 62.6 0 80V432c0 17.4 9.4 33.4 24.5 41.9s33.7 8.1 48.5-.9L361 297c14.3-8.7 23-24.2 23-41s-8.7-32.2-23-41L73 39z"/></svg></span></template>
<template id=fa-clock-rotate-left><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M75 75L41 41C25.9 25.9 0 36.6 0 57.9V168c0 13.3 10.7 24 24 24H134.1c21.4 0 32.1-25.9 17-41l-30.8-30.8C155 85.5 203 64 256 64c106 0 192 86 192 192s-86 192-192 192c-40.8 0-78.6-12.7-109.7-34.4c-14.5-10.1-34.4-6.6-44.6 7.9s-6.6 34.4 7.9 44.6C151.2 495 201.7 512 256 512c141.4 0 256-114.6 256-256S397.4 0 256 0C185.3 0 121.3 28.7 75 75zm181 53c-13.3 0-24 10.7-24 24V256c0 6.4 2.5 12.5 7 17l72 72c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-65-65V152c0-13.3-10.7-24-24-24z"/></svg></span></template>
<!-- Livereload script (if served using the cli tool) -->
<script>
const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
const wsAddress = wsProtocol + "//" + location.host + "/" + "__livereload";
const socket = new WebSocket(wsAddress);
socket.onmessage = function (event) {
if (event.data === "reload") {
socket.close();
location.reload();
}
};
window.onbeforeunload = function() {
socket.close();
}
</script>
<script>
window.playground_copyable = true;
</script>
<script src="../elasticlunr-ef4e11c1.min.js"></script>
<script src="../mark-09e88c2c.min.js"></script>
<script src="../searcher-c2a407aa.js"></script>
<script src="../clipboard-1626706a.min.js"></script>
<script src="../highlight-abc7f01d.js"></script>
<script src="../book-a0b12cfe.js"></script>
<!-- Custom JS scripts -->
</div>
</body>
</html>

View File

@@ -0,0 +1,607 @@
<!DOCTYPE HTML>
<html lang="en" class="light sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Creation of a simple ethernet network - Eden-sim - User Guide</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-de23e50b.svg">
<link rel="shortcut icon" href="../favicon-8114d1fc.png">
<link rel="stylesheet" href="../css/variables-8adf115d.css">
<link rel="stylesheet" href="../css/general-2459343d.css">
<link rel="stylesheet" href="../css/chrome-ae938929.css">
<link rel="stylesheet" href="../css/print-9e4910d8.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="../fonts/fonts-9644e21d.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" id="mdbook-highlight-css" href="../highlight-493f70e1.css">
<link rel="stylesheet" id="mdbook-tomorrow-night-css" href="../tomorrow-night-4c0ae647.css">
<link rel="stylesheet" id="mdbook-ayu-highlight-css" href="../ayu-highlight-3fdfc3ac.css">
<!-- Custom theme stylesheets -->
<!-- Provide site root and default themes to javascript -->
<script>
const path_to_root = "../";
const default_light_theme = "light";
const default_dark_theme = "navy";
window.path_to_searchindex_js = "../searchindex-43c2d326.js";
</script>
<!-- Start loading toc.js asap -->
<script src="../toc-81bc4348.js"></script>
</head>
<body>
<div id="mdbook-help-container">
<div id="mdbook-help-popup">
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
<div>
<p>Press <kbd></kbd> or <kbd></kbd> to navigate between chapters</p>
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
<p>Press <kbd>?</kbd> to show this help</p>
<p>Press <kbd>Esc</kbd> to hide this help</p>
</div>
</div>
</div>
<div id="mdbook-body-container">
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
let theme = localStorage.getItem('mdbook-theme');
let 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>
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
let theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
const html = document.documentElement;
html.classList.remove('light')
html.classList.add(theme);
html.classList.add("js");
</script>
<input type="checkbox" id="mdbook-sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
let sidebar = null;
const sidebar_toggle = document.getElementById("mdbook-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 = false;
}
if (sidebar === 'visible') {
sidebar_toggle.checked = true;
} else {
html.classList.remove('sidebar-visible');
}
</script>
<nav id="mdbook-sidebar" class="sidebar" aria-label="Table of contents">
<!-- populated by js -->
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
<noscript>
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
</noscript>
<div id="mdbook-sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<div id="mdbook-page-wrapper" class="page-wrapper">
<div class="page">
<div id="mdbook-menu-bar-hover-placeholder"></div>
<div id="mdbook-menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="mdbook-sidebar-toggle" class="icon-button" for="mdbook-sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="mdbook-sidebar">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M0 96C0 78.3 14.3 64 32 64H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H32C14.3 128 0 113.7 0 96zM0 256c0-17.7 14.3-32 32-32H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H32c-17.7 0-32-14.3-32-32zM448 416c0 17.7-14.3 32-32 32H32c-17.7 0-32-14.3-32-32s14.3-32 32-32H416c17.7 0 32 14.3 32 32z"/></svg></span>
</label>
<button id="mdbook-theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="mdbook-theme-list">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M371.3 367.1c27.3-3.9 51.9-19.4 67.2-42.9L600.2 74.1c12.6-19.5 9.4-45.3-7.6-61.2S549.7-4.4 531.1 9.6L294.4 187.2c-24 18-38.2 46.1-38.4 76.1L371.3 367.1zm-19.6 25.4l-116-104.4C175.9 290.3 128 339.6 128 400c0 3.9 .2 7.8 .6 11.6c1.8 17.5-10.2 36.4-27.8 36.4H96c-17.7 0-32 14.3-32 32s14.3 32 32 32H240c61.9 0 112-50.1 112-112c0-2.5-.1-5-.2-7.5z"/></svg></span>
</button>
<ul id="mdbook-theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-default_theme">Auto</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-ayu">Ayu</button></li>
</ul>
<button id="mdbook-search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="mdbook-searchbar">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352c79.5 0 144-64.5 144-144s-64.5-144-144-144S64 128.5 64 208s64.5 144 144 144z"/></svg></span>
</button>
</div>
<h1 class="menu-title">Eden-sim - User Guide</h1>
<div class="right-buttons">
<a href="../print.html" title="Print this book" aria-label="Print this book">
<span class=fa-svg id="print-button"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M128 0C92.7 0 64 28.7 64 64v96h64V64H354.7L384 93.3V160h64V93.3c0-17-6.7-33.3-18.7-45.3L400 18.7C388 6.7 371.7 0 354.7 0H128zM384 352v32 64H128V384 368 352H384zm64 32h32c17.7 0 32-14.3 32-32V256c0-35.3-28.7-64-64-64H64c-35.3 0-64 28.7-64 64v96c0 17.7 14.3 32 32 32H64v64c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V384zm-16-88c-13.3 0-24-10.7-24-24s10.7-24 24-24s24 10.7 24 24s-10.7 24-24 24z"/></svg></span>
</a>
</div>
</div>
<div id="mdbook-search-wrapper" class="hidden">
<form id="mdbook-searchbar-outer" class="searchbar-outer">
<div class="search-wrapper">
<input type="search" id="mdbook-searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="mdbook-searchresults-outer" aria-describedby="searchresults-header">
<div class="spinner-wrapper">
<span class=fa-svg id="fa-spin"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M304 48c0-26.5-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48s48-21.5 48-48zm0 416c0-26.5-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48s48-21.5 48-48zM48 304c26.5 0 48-21.5 48-48s-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48zm464-48c0-26.5-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48s48-21.5 48-48zM142.9 437c18.7-18.7 18.7-49.1 0-67.9s-49.1-18.7-67.9 0s-18.7 49.1 0 67.9s49.1 18.7 67.9 0zm0-294.2c18.7-18.7 18.7-49.1 0-67.9S93.7 56.2 75 75s-18.7 49.1 0 67.9s49.1 18.7 67.9 0zM369.1 437c18.7 18.7 49.1 18.7 67.9 0s18.7-49.1 0-67.9s-49.1-18.7-67.9 0s-18.7 49.1 0 67.9z"/></svg></span>
</div>
</div>
</form>
<div id="mdbook-searchresults-outer" class="searchresults-outer hidden">
<div id="mdbook-searchresults-header" class="searchresults-header"></div>
<ul id="mdbook-searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('mdbook-sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('mdbook-sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#mdbook-sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="mdbook-content" class="content">
<main>
<h1 id="creation-of-a-simple-ethernet-network"><a class="header" href="#creation-of-a-simple-ethernet-network">Creation of a simple ethernet network</a></h1>
<h2 id="introduction"><a class="header" href="#introduction">Introduction</a></h2>
<p>To perform a simulation with ns-3, you need to write a C++ program that describes the simulation to be performed. In this chapter, we will create such a simulation script able to simulate an Ethernet network composed of one switch to which three end stations are connected.</p>
<h2 id="first-simulation-script"><a class="header" href="#first-simulation-script">First simulation script</a></h2>
<p>Lets start by creating a script that runs a 10-second simulation. To do this, create a file called chapter1.cc in the scratch folder located in the ns-3 folder. In this file, copy the following lines:</p>
<pre><code class="language-c++">#include "ns3/simulator.h"
using namespace ns3;
NS_LOG_COMPONENT_DEFINE("Chapter 1");
int
main(int argc, char* argv[])
{
//Enable logging
LogComponentEnable("Chapter 1", LOG_LEVEL_INFO);
//Execute the simulation
NS_LOG_INFO("Start of the simulation");
Simulator::Stop(Seconds(10));
Simulator::Run();
Simulator::Destroy();
NS_LOG_INFO("End of the simulation");
return 0;
}
</code></pre>
<p>To run it, simply execute the following command from the folder where ns-3 is installed.</p>
<pre><code class="language-console">./ns3 run scratch/chapter1.cc
</code></pre>
<p>Congratulations, you have run your first simulation with ns-3! However, this simulation does not simulate anything.</p>
<h2 id="topology-description"><a class="header" href="#topology-description">Topology description</a></h2>
<p>Before simulating our Ethernet network, we must first describe it. To do this, lets start by adding the necessary dependencies.</p>
<pre><code class="language-c++">#include "ns3/simulator.h"
#include "ns3/core-module.h"
#include "ns3/node.h"
#include "ns3/drop-tail-queue.h"
#include "ns3/ethernet-net-device.h"
#include "ns3/ethernet-channel.h"
#include "ns3/switch-net-device.h"
[...]
</code></pre>
<p>Next, the topology is described as follows:</p>
<pre><code class="language-c++">[...]
//Enable logging
LogComponentEnable("Chapter 1", LOG_LEVEL_INFO);
//Create four nodes
Ptr&lt;Node&gt; n0 = CreateObject&lt;Node&gt;();
Names::Add("ES1", n0);
Ptr&lt;Node&gt; n1 = CreateObject&lt;Node&gt;();
Names::Add("ES2", n1);
Ptr&lt;Node&gt; n2 = CreateObject&lt;Node&gt;();
Names::Add("ES3", n2);
Ptr&lt;Node&gt; n3 = CreateObject&lt;Node&gt;();
Names::Add("SW", n3);
//Create and add a netDevice to each end-station node
Ptr&lt;EthernetNetDevice&gt; net0 = CreateObject&lt;EthernetNetDevice&gt;();
n0-&gt;AddDevice(net0);
Names::Add("ES1#01", net0);
Ptr&lt;EthernetNetDevice&gt; net1 = CreateObject&lt;EthernetNetDevice&gt;();
n1-&gt;AddDevice(net1);
Names::Add("ES2#01", net1);
Ptr&lt;EthernetNetDevice&gt; net2 = CreateObject&lt;EthernetNetDevice&gt;();
n2-&gt;AddDevice(net2);
Names::Add("ES3#01", net2);
//Create and add a netDevice to each switch port
Ptr&lt;EthernetNetDevice&gt; swnet0 = CreateObject&lt;EthernetNetDevice&gt;();
n3-&gt;AddDevice(swnet0);
Names::Add("SW#01", swnet0);
Ptr&lt;EthernetNetDevice&gt; swnet1 = CreateObject&lt;EthernetNetDevice&gt;();
n3-&gt;AddDevice(swnet1);
Names::Add("SW#02", swnet1);
Ptr&lt;EthernetNetDevice&gt; swnet2 = CreateObject&lt;EthernetNetDevice&gt;();
n3-&gt;AddDevice(swnet2);
Names::Add("SW#03", swnet2);
//Create Ethernet Channels and connect switch to the end-stations
Ptr&lt;EthernetChannel&gt; channel0 = CreateObject&lt;EthernetChannel&gt;();
net0-&gt;Attach(channel0);
swnet0-&gt;Attach(channel0);
Ptr&lt;EthernetChannel&gt; channel1 = CreateObject&lt;EthernetChannel&gt;();
net1-&gt;Attach(channel1);
swnet1-&gt;Attach(channel1);
Ptr&lt;EthernetChannel&gt; channel2 = CreateObject&lt;EthernetChannel&gt;();
net2-&gt;Attach(channel2);
swnet2-&gt;Attach(channel2);
//Create and add a switch net device to the switch node
Ptr&lt;SwitchNetDevice&gt; sw = CreateObject&lt;SwitchNetDevice&gt;();
n3-&gt;AddDevice(sw);
sw-&gt;AddSwitchPort(swnet0);
sw-&gt;AddSwitchPort(swnet1);
sw-&gt;AddSwitchPort(swnet2);
//Allocate Mac addresses to the netDevices
net0-&gt;SetAddress(Mac48Address::Allocate());
net1-&gt;SetAddress(Mac48Address::Allocate());
net2-&gt;SetAddress(Mac48Address::Allocate());
sw-&gt;SetAddress(Mac48Address::Allocate());
//Create two output port FIFOs for each netDevice.
for (int i=0; i&lt;2; i++){
net0-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;());
net1-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;());
net2-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;());
swnet0-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;());
swnet1-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;());
swnet2-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;());
}
[...]
</code></pre>
<p>In this code, the following six steps are performed:</p>
<ol>
<li><em>Creating nodes:</em> In this example, four nodes are created.</li>
<li><em>Creating NetDevices:</em> A NetDevice is a network interface in ns-3 terminology. Here, one NetDevice is created and added to each end-station node, and three NetDevices are created and added to the switch node.</li>
<li><em>Creating channels:</em> A channel is a link in ns-3 terminology in the case of the wired network considered here. Thus, three channels are created and attached to different NetDevices to connect the three end stations to the switch.</li>
<li><em>Creating SwitchNetDevices:</em> The SwitchNetDevice is the object that will perform switching between the switchs NetDevices. Here, a SwitchNetDevice object is created and attached to the switch node. The switch ports are also attached to it.</li>
<li><em>Allocation of Mac addresses:</em> For our example, four mac addresses are allocated using the iterator provided by ns-3.</li>
<li><em>Creation of output port queues:</em> For our example, two FIFOs are instantiated per NetDevices.</li>
</ol>
<p>At this stage, it is possible to run a simulation, but the output will be the same since no traffic is simulated.</p>
<h2 id="traffic-simulation"><a class="header" href="#traffic-simulation">Traffic simulation</a></h2>
<p>To send Ethernet frames in our network, we need to instantiate applications. To instantiate these applications, we must first add the following dependency.</p>
<pre><code class="language-c++">#include “ns3/ethernet-generator.h”
</code></pre>
<p>This dependency is part of Eden-sim and is used to transmit Q-Tagged Ethernet frames.</p>
<p>Next, lets add an application that sends a burst of two frames with a payload of 1400 bytes, a priority of 1, and a VLAN ID of 1 every 5 seconds. This application is hosted on node ES1. The frames are destined for ES3. Here is the code used to instantiate such an application:</p>
<pre><code class="language-c++">[...]
swnet2-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;());
}
//Application description
//ES1 -&gt; ES3 with priority 1
Ptr&lt;EthernetGenerator&gt; app0 = CreateObject&lt;EthernetGenerator&gt;();
app0-&gt;Setup(net0);
app0-&gt;SetAttribute("Address", AddressValue(net2-&gt;GetAddress()));
app0-&gt;SetAttribute("BurstSize", UintegerValue(2));
app0-&gt;SetAttribute("PayloadSize", UintegerValue(1400));
app0-&gt;SetAttribute("Period", TimeValue(Seconds(5)));
app0-&gt;SetAttribute("VlanID", UintegerValue(1));
app0-&gt;SetAttribute("PCP", UintegerValue(1));
n0-&gt;AddApplication(app0);
app0-&gt;SetStartTime(Seconds(0));
app0-&gt;SetStopTime(Seconds(10));
[...]
</code></pre>
<p>With this simulation script complete, you can run a simulation… And you should see nothing new.</p>
<p>Indeed, there is no indication for ns-3 to produce any output. So our frames are sent in our simulated network, but we have no output to confirm it. To display logs about our frames in the console, lets add a callback for the transmission and one for the reception.</p>
<pre><code class="language-c++">[...]
NS_LOG_COMPONENT_DEFINE("Chapter 1");
//A callback to log the pkt emission
static void
MacTxCallback(std::string context, Ptr&lt;const Packet&gt; p)
{
NS_LOG_INFO((Simulator::Now()).As(Time::S) &lt;&lt; " \t" &lt;&lt; context &lt;&lt; " : Pkt #" &lt;&lt; p-&gt;GetUid() &lt;&lt; " sent!");
}
//A callback to log the pkt reception
static void
MacRxCallback(std::string context, Ptr&lt;const Packet&gt; p)
{
NS_LOG_INFO((Simulator::Now()).As(Time::S) &lt;&lt; " \t" &lt;&lt; context &lt;&lt; " : Pkt #" &lt;&lt; p-&gt;GetUid() &lt;&lt; " received!");
}
[...]
</code></pre>
<pre><code class="language-c++">[...]
app0-&gt;SetStopTime(Seconds(10));
//Callback declarations
//Callback to display the packet sent log
std::string context = Names::FindName(n0) + ":" + Names::FindName(net0);
net0-&gt;TraceConnectWithoutContext("MacTx", MakeBoundCallback(&amp;MacTxCallback, context));
//Callback to display the packet received log
context = Names::FindName(n2) + ":" + Names::FindName(net2);
net2-&gt;TraceConnectWithoutContext("MacRx", MakeBoundCallback(&amp;MacRxCallback, context));
[...]
</code></pre>
<p>If you run the simulation again, you should get the following output.</p>
<pre><code class="language-console">$ ./ns3 run scratch/book.cc
[0/2] Re-checking globbed directories...
[2/2] Linking CXX executable ../build/scratch/ns3.40-book-default
Start of the simulation
+0s ES1:ES1#01 : Pkt #0 sent!
+0s ES1:ES1#01 : Pkt #1 sent!
+5s ES1:ES1#01 : Pkt #2 sent!
+5s ES1:ES1#01 : Pkt #3 sent!
End of the simulation
</code></pre>
<p>We can see that four frames are successfully sent by ES1 but are never received by ES3. This is because, after the first hop, the frames are received by the switch but it does not know which port to send them to. It is therefore necessary to add a static forwarding configuration to our switch.</p>
<h2 id="network-configuration"><a class="header" href="#network-configuration">Network configuration</a></h2>
<p>Unlike plug-and-play switches, the switches simulated by Eden-sim are designed for critical embedded networks. To guarantee network determinism, these switches do not implement dynamic mechanisms such as mac learning. They must therefore be configured statically before the simulation begins.</p>
<p>Here, the only configuration missing to transmit frames to ES3 is the configuration of the static switching table. It is possible to add an entry to this table as follows:</p>
<pre><code class="language-c++">[...]
swnet2-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;());
}
//Add a forwarding table entry
sw-&gt;AddForwardingTableEntry(Mac48Address::ConvertFrom(net2-&gt;GetAddress()), 1, {swnet2});
[...]
</code></pre>
<p>After this configuration, running the simulation produces the following output, which finally indicates the transmission and reception of frames.</p>
<pre><code class="language-console">$ ./ns3 run scratch/book.cc
[0/2] Re-checking globbed directories...
[2/2] Linking CXX executable ../build/scratch/ns3.40-book-default
Start of the simulation
+0s ES1:ES1#01 : Pkt #0 sent!
+0s ES1:ES1#01 : Pkt #1 sent!
+2.293e-05s ES3:ES3#01 : Pkt #0 received!
+3.4466e-05s ES3:ES3#01 : Pkt #1 received!
+5s ES1:ES1#01 : Pkt #2 sent!
+5s ES1:ES1#01 : Pkt #3 sent!
+5.00002s ES3:ES3#01 : Pkt #2 received!
+5.00003s ES3:ES3#01 : Pkt #3 received!
End of the simulation
</code></pre>
<h2 id="final-simulation-script"><a class="header" href="#final-simulation-script">Final simulation script</a></h2>
<p>Here is the simulation script you should have at the end of this chapter.</p>
<pre><code class="language-c++">#include "ns3/simulator.h"
#include "ns3/core-module.h"
#include "ns3/node.h"
#include "ns3/drop-tail-queue.h"
#include "ns3/ethernet-net-device.h"
#include "ns3/ethernet-channel.h"
#include "ns3/switch-net-device.h"
#include "ns3/ethernet-generator.h"
using namespace ns3;
NS_LOG_COMPONENT_DEFINE("Chapter 1");
//A callback to log the pkt emission
static void
MacTxCallback(std::string context, Ptr&lt;const Packet&gt; p)
{
NS_LOG_INFO((Simulator::Now()).As(Time::S) &lt;&lt; " \t" &lt;&lt; context &lt;&lt; " : Pkt #" &lt;&lt; p-&gt;GetUid() &lt;&lt; " sent!");
}
//A callback to log the pkt reception
static void
MacRxCallback(std::string context, Ptr&lt;const Packet&gt; p)
{
NS_LOG_INFO((Simulator::Now()).As(Time::S) &lt;&lt; " \t" &lt;&lt; context &lt;&lt; " : Pkt #" &lt;&lt; p-&gt;GetUid() &lt;&lt; " received!");
}
int
main(int argc, char* argv[])
{
//Enable logging
LogComponentEnable("Chapter 1", LOG_LEVEL_INFO);
//Create four nodes
Ptr&lt;Node&gt; n0 = CreateObject&lt;Node&gt;();
Names::Add("ES1", n0);
Ptr&lt;Node&gt; n1 = CreateObject&lt;Node&gt;();
Names::Add("ES2", n1);
Ptr&lt;Node&gt; n2 = CreateObject&lt;Node&gt;();
Names::Add("ES3", n2);
Ptr&lt;Node&gt; n3 = CreateObject&lt;Node&gt;();
Names::Add("SW", n3);
//Create and add a netDevice to each end-station node
Ptr&lt;EthernetNetDevice&gt; net0 = CreateObject&lt;EthernetNetDevice&gt;();
n0-&gt;AddDevice(net0);
Names::Add("ES1#01", net0);
Ptr&lt;EthernetNetDevice&gt; net1 = CreateObject&lt;EthernetNetDevice&gt;();
n1-&gt;AddDevice(net1);
Names::Add("ES2#01", net1);
Ptr&lt;EthernetNetDevice&gt; net2 = CreateObject&lt;EthernetNetDevice&gt;();
n2-&gt;AddDevice(net2);
Names::Add("ES3#01", net2);
//Create and add a netDevice to each switch port
Ptr&lt;EthernetNetDevice&gt; swnet0 = CreateObject&lt;EthernetNetDevice&gt;();
n3-&gt;AddDevice(swnet0);
Names::Add("SW#01", swnet0);
Ptr&lt;EthernetNetDevice&gt; swnet1 = CreateObject&lt;EthernetNetDevice&gt;();
n3-&gt;AddDevice(swnet1);
Names::Add("SW#02", swnet1);
Ptr&lt;EthernetNetDevice&gt; swnet2 = CreateObject&lt;EthernetNetDevice&gt;();
n3-&gt;AddDevice(swnet2);
Names::Add("SW#03", swnet2);
//Create Ethernet Channels and connect switch to the end-stations
Ptr&lt;EthernetChannel&gt; channel0 = CreateObject&lt;EthernetChannel&gt;();
net0-&gt;Attach(channel0);
swnet0-&gt;Attach(channel0);
Ptr&lt;EthernetChannel&gt; channel1 = CreateObject&lt;EthernetChannel&gt;();
net1-&gt;Attach(channel1);
swnet1-&gt;Attach(channel1);
Ptr&lt;EthernetChannel&gt; channel2 = CreateObject&lt;EthernetChannel&gt;();
net2-&gt;Attach(channel2);
swnet2-&gt;Attach(channel2);
//Create and add a switch net device to the switch node
Ptr&lt;SwitchNetDevice&gt; sw = CreateObject&lt;SwitchNetDevice&gt;();
n3-&gt;AddDevice(sw);
sw-&gt;AddSwitchPort(swnet0);
sw-&gt;AddSwitchPort(swnet1);
sw-&gt;AddSwitchPort(swnet2);
//Allocate Mac addresses to the netDevices
net0-&gt;SetAddress(Mac48Address::Allocate());
net1-&gt;SetAddress(Mac48Address::Allocate());
net2-&gt;SetAddress(Mac48Address::Allocate());
sw-&gt;SetAddress(Mac48Address::Allocate());
//Create 2 output port FIFOs for each netDevice.
for (int i=0; i&lt;2; i++){
net0-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;());
net1-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;());
net2-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;());
swnet0-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;());
swnet1-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;());
swnet2-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;());
}
//Add a forwarding table entry
sw-&gt;AddForwardingTableEntry(Mac48Address::ConvertFrom(net2-&gt;GetAddress()), 1, {swnet2});
//Application description
//ES1 -&gt; ES3 with priority 1
Ptr&lt;EthernetGenerator&gt; app0 = CreateObject&lt;EthernetGenerator&gt;();
app0-&gt;Setup(net0);
app0-&gt;SetAttribute("Address", AddressValue(net2-&gt;GetAddress()));
app0-&gt;SetAttribute("BurstSize", UintegerValue(2));
app0-&gt;SetAttribute("PayloadSize", UintegerValue(1400));
app0-&gt;SetAttribute("Period", TimeValue(Seconds(5)));
app0-&gt;SetAttribute("VlanID", UintegerValue(1));
app0-&gt;SetAttribute("PCP", UintegerValue(1));
n0-&gt;AddApplication(app0);
app0-&gt;SetStartTime(Seconds(0));
app0-&gt;SetStopTime(Seconds(10));
//Callback declarations
//Callback to display the packet sent log
std::string context = Names::FindName(n0) + ":" + Names::FindName(net0);
net0-&gt;TraceConnectWithoutContext("MacTx", MakeBoundCallback(&amp;MacTxCallback, context));
//Callback to display the packet received log
context = Names::FindName(n2) + ":" + Names::FindName(net2);
net2-&gt;TraceConnectWithoutContext("MacRx", MakeBoundCallback(&amp;MacRxCallback, context));
//Execute the simulation
NS_LOG_INFO("Start of the simulation");
Simulator::Stop(Seconds(10));
Simulator::Run();
Simulator::Destroy();
NS_LOG_INFO("End of the simulation");
return 0;
}
</code></pre>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../prerequisites.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M41.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l160 160c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L109.3 256 246.6 118.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-160 160z"/></svg></span>
</a>
<a rel="next prefetch" href="../getting_stated/network_customization.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M278.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-160 160c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L210.7 256 73.4 118.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l160 160z"/></svg></span>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../prerequisites.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M41.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l160 160c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L109.3 256 246.6 118.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-160 160z"/></svg></span>
</a>
<a rel="next prefetch" href="../getting_stated/network_customization.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M278.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-160 160c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L210.7 256 73.4 118.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l160 160z"/></svg></span>
</a>
</nav>
</div>
<template id=fa-eye><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M288 32c-80.8 0-145.5 36.8-192.6 80.6C48.6 156 17.3 208 2.5 243.7c-3.3 7.9-3.3 16.7 0 24.6C17.3 304 48.6 356 95.4 399.4C142.5 443.2 207.2 480 288 480s145.5-36.8 192.6-80.6c46.8-43.5 78.1-95.4 93-131.1c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C433.5 68.8 368.8 32 288 32zM432 256c0 79.5-64.5 144-144 144s-144-64.5-144-144s64.5-144 144-144s144 64.5 144 144zM288 192c0 35.3-28.7 64-64 64c-11.5 0-22.3-3-31.6-8.4c-.2 2.8-.4 5.5-.4 8.4c0 53 43 96 96 96s96-43 96-96s-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6z"/></svg></span></template>
<template id=fa-eye-slash><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M38.8 5.1C28.4-3.1 13.3-1.2 5.1 9.2S-1.2 34.7 9.2 42.9l592 464c10.4 8.2 25.5 6.3 33.7-4.1s6.3-25.5-4.1-33.7L525.6 386.7c39.6-40.6 66.4-86.1 79.9-118.4c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C465.5 68.8 400.8 32 320 32c-68.2 0-125 26.3-169.3 60.8L38.8 5.1zM223.1 149.5C248.6 126.2 282.7 112 320 112c79.5 0 144 64.5 144 144c0 24.9-6.3 48.3-17.4 68.7L408 294.5c5.2-11.8 8-24.8 8-38.5c0-53-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6c0 10.2-2.4 19.8-6.6 28.3l-90.3-70.8zm223.1 298L373 389.9c-16.4 6.5-34.3 10.1-53 10.1c-79.5 0-144-64.5-144-144c0-6.9 .5-13.6 1.4-20.2L83.1 161.5C60.3 191.2 44 220.8 34.5 243.7c-3.3 7.9-3.3 16.7 0 24.6c14.9 35.7 46.2 87.7 93 131.1C174.5 443.2 239.2 480 320 480c47.8 0 89.9-12.9 126.2-32.5z"/></svg></span></template>
<template id=fa-copy><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M502.6 70.63l-61.25-61.25C435.4 3.371 427.2 0 418.7 0H255.1c-35.35 0-64 28.66-64 64l.0195 256C192 355.4 220.7 384 256 384h192c35.2 0 64-28.8 64-64V93.25C512 84.77 508.6 76.63 502.6 70.63zM464 320c0 8.836-7.164 16-16 16H255.1c-8.838 0-16-7.164-16-16L239.1 64.13c0-8.836 7.164-16 16-16h128L384 96c0 17.67 14.33 32 32 32h47.1V320zM272 448c0 8.836-7.164 16-16 16H63.1c-8.838 0-16-7.164-16-16L47.98 192.1c0-8.836 7.164-16 16-16H160V128H63.99c-35.35 0-64 28.65-64 64l.0098 256C.002 483.3 28.66 512 64 512h192c35.2 0 64-28.8 64-64v-32h-47.1L272 448z"/></svg></span></template>
<template id=fa-play><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M73 39c-14.8-9.1-33.4-9.4-48.5-.9S0 62.6 0 80V432c0 17.4 9.4 33.4 24.5 41.9s33.7 8.1 48.5-.9L361 297c14.3-8.7 23-24.2 23-41s-8.7-32.2-23-41L73 39z"/></svg></span></template>
<template id=fa-clock-rotate-left><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M75 75L41 41C25.9 25.9 0 36.6 0 57.9V168c0 13.3 10.7 24 24 24H134.1c21.4 0 32.1-25.9 17-41l-30.8-30.8C155 85.5 203 64 256 64c106 0 192 86 192 192s-86 192-192 192c-40.8 0-78.6-12.7-109.7-34.4c-14.5-10.1-34.4-6.6-44.6 7.9s-6.6 34.4 7.9 44.6C151.2 495 201.7 512 256 512c141.4 0 256-114.6 256-256S397.4 0 256 0C185.3 0 121.3 28.7 75 75zm181 53c-13.3 0-24 10.7-24 24V256c0 6.4 2.5 12.5 7 17l72 72c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-65-65V152c0-13.3-10.7-24-24-24z"/></svg></span></template>
<!-- Livereload script (if served using the cli tool) -->
<script>
const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
const wsAddress = wsProtocol + "//" + location.host + "/" + "__livereload";
const socket = new WebSocket(wsAddress);
socket.onmessage = function (event) {
if (event.data === "reload") {
socket.close();
location.reload();
}
};
window.onbeforeunload = function() {
socket.close();
}
</script>
<script>
window.playground_copyable = true;
</script>
<script src="../elasticlunr-ef4e11c1.min.js"></script>
<script src="../mark-09e88c2c.min.js"></script>
<script src="../searcher-c2a407aa.js"></script>
<script src="../clipboard-1626706a.min.js"></script>
<script src="../highlight-abc7f01d.js"></script>
<script src="../book-a0b12cfe.js"></script>
<!-- Custom JS scripts -->
</div>
</body>
</html>

View File

@@ -0,0 +1,936 @@
<!DOCTYPE HTML>
<html lang="en" class="light sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Creation of a simple tsn network - Eden-sim - User Guide</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-de23e50b.svg">
<link rel="shortcut icon" href="../favicon-8114d1fc.png">
<link rel="stylesheet" href="../css/variables-8adf115d.css">
<link rel="stylesheet" href="../css/general-2459343d.css">
<link rel="stylesheet" href="../css/chrome-ae938929.css">
<link rel="stylesheet" href="../css/print-9e4910d8.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="../fonts/fonts-9644e21d.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" id="mdbook-highlight-css" href="../highlight-493f70e1.css">
<link rel="stylesheet" id="mdbook-tomorrow-night-css" href="../tomorrow-night-4c0ae647.css">
<link rel="stylesheet" id="mdbook-ayu-highlight-css" href="../ayu-highlight-3fdfc3ac.css">
<!-- Custom theme stylesheets -->
<!-- Provide site root and default themes to javascript -->
<script>
const path_to_root = "../";
const default_light_theme = "light";
const default_dark_theme = "navy";
window.path_to_searchindex_js = "../searchindex-43c2d326.js";
</script>
<!-- Start loading toc.js asap -->
<script src="../toc-81bc4348.js"></script>
</head>
<body>
<div id="mdbook-help-container">
<div id="mdbook-help-popup">
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
<div>
<p>Press <kbd></kbd> or <kbd></kbd> to navigate between chapters</p>
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
<p>Press <kbd>?</kbd> to show this help</p>
<p>Press <kbd>Esc</kbd> to hide this help</p>
</div>
</div>
</div>
<div id="mdbook-body-container">
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
let theme = localStorage.getItem('mdbook-theme');
let 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>
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
let theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
const html = document.documentElement;
html.classList.remove('light')
html.classList.add(theme);
html.classList.add("js");
</script>
<input type="checkbox" id="mdbook-sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
let sidebar = null;
const sidebar_toggle = document.getElementById("mdbook-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 = false;
}
if (sidebar === 'visible') {
sidebar_toggle.checked = true;
} else {
html.classList.remove('sidebar-visible');
}
</script>
<nav id="mdbook-sidebar" class="sidebar" aria-label="Table of contents">
<!-- populated by js -->
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
<noscript>
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
</noscript>
<div id="mdbook-sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<div id="mdbook-page-wrapper" class="page-wrapper">
<div class="page">
<div id="mdbook-menu-bar-hover-placeholder"></div>
<div id="mdbook-menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="mdbook-sidebar-toggle" class="icon-button" for="mdbook-sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="mdbook-sidebar">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M0 96C0 78.3 14.3 64 32 64H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H32C14.3 128 0 113.7 0 96zM0 256c0-17.7 14.3-32 32-32H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H32c-17.7 0-32-14.3-32-32zM448 416c0 17.7-14.3 32-32 32H32c-17.7 0-32-14.3-32-32s14.3-32 32-32H416c17.7 0 32 14.3 32 32z"/></svg></span>
</label>
<button id="mdbook-theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="mdbook-theme-list">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M371.3 367.1c27.3-3.9 51.9-19.4 67.2-42.9L600.2 74.1c12.6-19.5 9.4-45.3-7.6-61.2S549.7-4.4 531.1 9.6L294.4 187.2c-24 18-38.2 46.1-38.4 76.1L371.3 367.1zm-19.6 25.4l-116-104.4C175.9 290.3 128 339.6 128 400c0 3.9 .2 7.8 .6 11.6c1.8 17.5-10.2 36.4-27.8 36.4H96c-17.7 0-32 14.3-32 32s14.3 32 32 32H240c61.9 0 112-50.1 112-112c0-2.5-.1-5-.2-7.5z"/></svg></span>
</button>
<ul id="mdbook-theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-default_theme">Auto</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-ayu">Ayu</button></li>
</ul>
<button id="mdbook-search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="mdbook-searchbar">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352c79.5 0 144-64.5 144-144s-64.5-144-144-144S64 128.5 64 208s64.5 144 144 144z"/></svg></span>
</button>
</div>
<h1 class="menu-title">Eden-sim - User Guide</h1>
<div class="right-buttons">
<a href="../print.html" title="Print this book" aria-label="Print this book">
<span class=fa-svg id="print-button"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M128 0C92.7 0 64 28.7 64 64v96h64V64H354.7L384 93.3V160h64V93.3c0-17-6.7-33.3-18.7-45.3L400 18.7C388 6.7 371.7 0 354.7 0H128zM384 352v32 64H128V384 368 352H384zm64 32h32c17.7 0 32-14.3 32-32V256c0-35.3-28.7-64-64-64H64c-35.3 0-64 28.7-64 64v96c0 17.7 14.3 32 32 32H64v64c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V384zm-16-88c-13.3 0-24-10.7-24-24s10.7-24 24-24s24 10.7 24 24s-10.7 24-24 24z"/></svg></span>
</a>
</div>
</div>
<div id="mdbook-search-wrapper" class="hidden">
<form id="mdbook-searchbar-outer" class="searchbar-outer">
<div class="search-wrapper">
<input type="search" id="mdbook-searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="mdbook-searchresults-outer" aria-describedby="searchresults-header">
<div class="spinner-wrapper">
<span class=fa-svg id="fa-spin"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M304 48c0-26.5-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48s48-21.5 48-48zm0 416c0-26.5-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48s48-21.5 48-48zM48 304c26.5 0 48-21.5 48-48s-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48zm464-48c0-26.5-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48s48-21.5 48-48zM142.9 437c18.7-18.7 18.7-49.1 0-67.9s-49.1-18.7-67.9 0s-18.7 49.1 0 67.9s49.1 18.7 67.9 0zm0-294.2c18.7-18.7 18.7-49.1 0-67.9S93.7 56.2 75 75s-18.7 49.1 0 67.9s49.1 18.7 67.9 0zM369.1 437c18.7 18.7 49.1 18.7 67.9 0s18.7-49.1 0-67.9s-49.1-18.7-67.9 0s-18.7 49.1 0 67.9z"/></svg></span>
</div>
</div>
</form>
<div id="mdbook-searchresults-outer" class="searchresults-outer hidden">
<div id="mdbook-searchresults-header" class="searchresults-header"></div>
<ul id="mdbook-searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('mdbook-sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('mdbook-sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#mdbook-sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="mdbook-content" class="content">
<main>
<h1 id="creation-of-a-simple-tsn-network"><a class="header" href="#creation-of-a-simple-tsn-network">Creation of a simple tsn network</a></h1>
<h2 id="introduction"><a class="header" href="#introduction">Introduction</a></h2>
<p>In this chapter, we will explore how to transform the Ethernet network simulation script from the previous chapter into a TSN network simulation script. Then, we will discuss how to instantiate and configure the various TSN mechanisms supported by the simulation library.</p>
<p>Note that the operation and configuration of TSN mechanisms will not be explained in depth. This chapter assumes that the reader is familiar with the details of the mechanisms implemented.</p>
<h2 id="from-ethernet-to-tsn-simulation"><a class="header" href="#from-ethernet-to-tsn-simulation">From Ethernet to TSN simulation</a></h2>
<p>Lets start by importing two new objects: TsnNode and TsnNetDevice.</p>
<pre><code class="language-c++">[...]
#include "ns3/tsn-node.h"
#include "ns3/tsn-net-device.h"
[...]
</code></pre>
<p>Next, it is necessary to replace the node and EthernetNetDevice objects with their TSN versions in order to instantiate the various TSN mechanisms described below.</p>
<pre><code class="language-c++">[...]
//Create four nodes
Ptr&lt;TsnNode&gt; n0 = CreateObject&lt;TsnNode&gt;();
Names::Add("ES1", n0);
Ptr&lt;TsnNode&gt; n1 = CreateObject&lt;TsnNode&gt;();
Names::Add("ES2", n1);
Ptr&lt;TsnNode&gt; n2 = CreateObject&lt;TsnNode&gt;();
Names::Add("ES3", n2);
Ptr&lt;TsnNode&gt; n3 = CreateObject&lt;TsnNode&gt;();
Names::Add("SW", n3);
//Create and add a netDevice to each end-station node
Ptr&lt;TsnNetDevice&gt; net0 = CreateObject&lt;TsnNetDevice&gt;();
n0-&gt;AddDevice(net0);
Names::Add("ES1#01", net0);
Ptr&lt;TsnNetDevice&gt; net1 = CreateObject&lt;TsnNetDevice&gt;();
n1-&gt;AddDevice(net1);
Names::Add("ES2#01", net1);
Ptr&lt;TsnNetDevice&gt; net2 = CreateObject&lt;TsnNetDevice&gt;();
n2-&gt;AddDevice(net2);
Names::Add("ES3#01", net2);
//Create and add a netDevice to each switch port
Ptr&lt;TsnNetDevice&gt; swnet0 = CreateObject&lt;TsnNetDevice&gt;();
n3-&gt;AddDevice(swnet0);
Names::Add("SW#01", swnet0);
Ptr&lt;TsnNetDevice&gt; swnet1 = CreateObject&lt;TsnNetDevice&gt;();
n3-&gt;AddDevice(swnet1);
Names::Add("SW#02", swnet1);
Ptr&lt;TsnNetDevice&gt; swnet2 = CreateObject&lt;TsnNetDevice&gt;();
n3-&gt;AddDevice(swnet2);
Names::Add("SW#03", swnet2);
[...]
</code></pre>
<p>At this stage, it is possible to run a simulation, but the result will be identical to a simple Ethernet network.</p>
<p>To simplify the illustration of the latency control mechanisms (CBS and TAS), we can make the following modifications to the application:</p>
<pre><code class="language-c++">[...]
//Application description
//ES1 -&gt; ES3 with priority 1
Ptr&lt;EthernetGenerator&gt; app0 = CreateObject&lt;EthernetGenerator&gt;();
app0-&gt;Setup(net0);
app0-&gt;SetAttribute("Address", AddressValue(net2-&gt;GetAddress()));
app0-&gt;SetAttribute("BurstSize", UintegerValue(5));
app0-&gt;SetAttribute("PayloadSize", UintegerValue(1400));
app0-&gt;SetAttribute("Period", TimeValue(Seconds(5)));
app0-&gt;SetAttribute("VlanID", UintegerValue(1));
app0-&gt;SetAttribute("PCP", UintegerValue(1));
n0-&gt;AddApplication(app0);
app0-&gt;SetStartTime(Seconds(0));
app0-&gt;SetStopTime(Seconds(10));
[...]
</code></pre>
<p>The output of a simulation should look like this:</p>
<pre><code class="language-console">[0/2] Re-checking globbed directories...
[2/2] Linking CXX executable ../build/scratch/ns3.40-book-default
Start of the simulation
+0s ES1:ES1#01 : Pkt #0 sent!
+0s ES1:ES1#01 : Pkt #1 sent!
+0s ES1:ES1#01 : Pkt #2 sent!
+0s ES1:ES1#01 : Pkt #3 sent!
+0s ES1:ES1#01 : Pkt #4 sent!
+0.000233905s ES3:ES3#01 : Pkt #0 received!
+0.000349265s ES3:ES3#01 : Pkt #1 received!
+0.000464625s ES3:ES3#01 : Pkt #2 received!
+0.000579985s ES3:ES3#01 : Pkt #3 received!
+0.000695345s ES3:ES3#01 : Pkt #4 received!
+5s ES1:ES1#01 : Pkt #5 sent!
+5s ES1:ES1#01 : Pkt #6 sent!
+5s ES1:ES1#01 : Pkt #7 sent!
+5s ES1:ES1#01 : Pkt #8 sent!
+5s ES1:ES1#01 : Pkt #9 sent!
+5.00023s ES3:ES3#01 : Pkt #5 received!
+5.00035s ES3:ES3#01 : Pkt #6 received!
+5.00046s ES3:ES3#01 : Pkt #7 received!
+5.00058s ES3:ES3#01 : Pkt #8 received!
+5.0007s ES3:ES3#01 : Pkt #9 received!
End of the simulation
</code></pre>
<h2 id="cbs"><a class="header" href="#cbs">CBS</a></h2>
<p>To instantiate a CBS, we must first add its dependency.</p>
<pre><code class="language-c++">#include "ns3/cbs.h"
</code></pre>
<p>It is then possible to instantiate a CBS and link it to an output port queue. In the following example, we instantiate the CBS on the output port of the transmitting end station.</p>
<pre><code class="language-c++">[...]
//Create 2 output port FIFOs for each netDevice.
Ptr&lt;Cbs&gt; cbs = CreateObject&lt;Cbs&gt;();
cbs-&gt;SetTsnNetDevice(net0);
cbs-&gt;SetAttribute("IdleSlope", DataRateValue(DataRate("20Kb/s")));
cbs-&gt;SetAttribute("portTransmitRate", DataRateValue(DataRate("100Mb/s")));
net0-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;()); //FIFO 0
net0-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;(), cbs); //FIFO 1
for (int i=0; i&lt;2; i++){
net1-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;());
net2-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;());
swnet0-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;());
swnet1-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;());
swnet2-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;());
}
[...]
</code></pre>
<p>When launching the simulation, we can now see that the reception of burst frames is spread out over time due to the waiting time imposed by the CBS credit reload on the emission port.</p>
<pre><code class="language-console">[0/2] Re-checking globbed directories...
[2/2] Linking CXX executable ../build/scratch/ns3.40-book-default
Start of the simulation
+0s ES1:ES1#01 : Pkt #0 sent!
+0s ES1:ES1#01 : Pkt #1 sent!
+0s ES1:ES1#01 : Pkt #2 sent!
+0s ES1:ES1#01 : Pkt #3 sent!
+0s ES1:ES1#01 : Pkt #4 sent!
+0.000233905s ES3:ES3#01 : Pkt #0 received!
+0.577031s ES3:ES3#01 : Pkt #1 received!
+1.15383s ES3:ES3#01 : Pkt #2 received!
+1.73063s ES3:ES3#01 : Pkt #3 received!
+2.30743s ES3:ES3#01 : Pkt #4 received!
+5s ES1:ES1#01 : Pkt #5 sent!
+5s ES1:ES1#01 : Pkt #6 sent!
+5s ES1:ES1#01 : Pkt #7 sent!
+5s ES1:ES1#01 : Pkt #8 sent!
+5s ES1:ES1#01 : Pkt #9 sent!
+5.00023s ES3:ES3#01 : Pkt #5 received!
+5.57703s ES3:ES3#01 : Pkt #6 received!
+6.15383s ES3:ES3#01 : Pkt #7 received!
+6.73063s ES3:ES3#01 : Pkt #8 received!
+7.30743s ES3:ES3#01 : Pkt #9 received!
End of the simulation
</code></pre>
<h2 id="tas"><a class="header" href="#tas">TAS</a></h2>
<p>To instanciate TAS, we need to add a clock to the TsnNode, add GCL entries to the net device and add 8 FIFOs to the output ports. It can be done as follows:</p>
<pre><code class="language-c++">[...]
//Add a perfect clock to the SW node
n3-&gt;AddClock(CreateObject&lt;Clock&gt;());
[...]
//Create 8 output port FIFOs for each netDevice.
Ptr&lt;Cbs&gt; cbs = CreateObject&lt;Cbs&gt;();
cbs-&gt;SetTsnNetDevice(net0);
cbs-&gt;SetAttribute("IdleSlope", DataRateValue(DataRate("20Kb/s")));
cbs-&gt;SetAttribute("portTransmitRate", DataRateValue(DataRate("100Mb/s")));
net0-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;()); //FIFO 0
net0-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;(), cbs); //FIFO 1
for (int i=0; i&lt;6; i++){
net0-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;()); //FIFO 0
}
for (int i=0; i&lt;8; i++){
net1-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;());
net2-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;());
swnet0-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;());
swnet1-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;());
swnet2-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;());
}
[...]
//Configure TAS schedule
swnet2-&gt;AddGclEntry(Time(Seconds(2)), 0); //All gates are close
swnet2-&gt;AddGclEntry(Time(Seconds(3)), 2); //Only the gate of the FIFO 1 is open
swnet2-&gt;StartTas();
[...]
</code></pre>
<p>In this example, a TAS schedule is added to the switchs output port, used by the flow. This schedule is designed to delay the frames of the two bursts by approximately two seconds compared to the previous example. The result obtained is as follows.</p>
<pre><code class="language-console">[0/2] Re-checking globbed directories...
[2/2] Linking CXX executable ../build/scratch/ns3.40-book-default
Start of the simulation
+0s ES1:ES1#01 : Pkt #0 sent!
+0s ES1:ES1#01 : Pkt #1 sent!
+0s ES1:ES1#01 : Pkt #2 sent!
+0s ES1:ES1#01 : Pkt #3 sent!
+0s ES1:ES1#01 : Pkt #4 sent!
+2.00011s ES3:ES3#01 : Pkt #0 received!
+2.00023s ES3:ES3#01 : Pkt #1 received!
+2.00035s ES3:ES3#01 : Pkt #2 received!
+2.00046s ES3:ES3#01 : Pkt #3 received!
+2.30743s ES3:ES3#01 : Pkt #4 received!
+5s ES1:ES1#01 : Pkt #5 sent!
+5s ES1:ES1#01 : Pkt #6 sent!
+5s ES1:ES1#01 : Pkt #7 sent!
+5s ES1:ES1#01 : Pkt #8 sent!
+5s ES1:ES1#01 : Pkt #9 sent!
+7.00011s ES3:ES3#01 : Pkt #5 received!
+7.00023s ES3:ES3#01 : Pkt #6 received!
+7.00035s ES3:ES3#01 : Pkt #7 received!
+7.00046s ES3:ES3#01 : Pkt #8 received!
+7.30743s ES3:ES3#01 : Pkt #9 received!
End of the simulation
</code></pre>
<h2 id="gptp"><a class="header" href="#gptp">gPTP</a></h2>
<p>To synchronize the nodes in our network using gPTP, several changes must be made. Lets start with the includes.</p>
<pre><code class="language-c++">[...]
#include "ns3/clock-constant-drift.h"
#include "ns3/gPTP.h"
#include "ns3/ethernet-header2.h"
[...]
</code></pre>
<p>Next, lets modify the callbacks that log packet transmission and reception so that events are only logged if the VLAN ID matches the VLAN ID of the flows going from ES1 to ES3. This change prevents the output from being flooded with logs concerning the transmission or reception of synchronization frames. We also add a callback to log the difference between the perfect clock (the simulation time) and the device clock after each correction to verify that gPTP is working properly.</p>
<pre><code class="language-c++">//A callback to log the pkt emission
static void
MacTxCallback(std::string context, Ptr&lt;const Packet&gt; p)
{
Ptr&lt;Packet&gt; pkt = p-&gt;Copy();
EthernetHeader2 ethHeader;
pkt-&gt;RemoveHeader(ethHeader);
if (ethHeader.GetVid() == 1) {
NS_LOG_INFO((Simulator::Now()).As(Time::S) &lt;&lt; " \t" &lt;&lt; context &lt;&lt; " : Pkt #" &lt;&lt; p-&gt;GetUid() &lt;&lt; " sent!");
}
}
//A callback to log the pkt reception
static void
MacRxCallback(std::string context, Ptr&lt;const Packet&gt; p)
{
Ptr&lt;Packet&gt; pkt = p-&gt;Copy();
EthernetHeader2 ethHeader;
pkt-&gt;RemoveHeader(ethHeader);
if (ethHeader.GetVid() == 1) {
NS_LOG_INFO((Simulator::Now()).As(Time::S) &lt;&lt; " \t" &lt;&lt; context &lt;&lt; " : Pkt #" &lt;&lt; p-&gt;GetUid() &lt;&lt; " received!");
}
}
//A callback to log clock offset after correction
static void
ClockAfterCorrectionCallback(std::string context, Time clockValue)
{
NS_LOG_INFO("[GPTP] At " &lt;&lt; Simulator::Now() &lt;&lt; " on "&lt;&lt; context &lt;&lt; " clock value after correction = " &lt;&lt; clockValue.GetNanoSeconds() &lt;&lt; "ns (error = "&lt;&lt; (Simulator::Now()-clockValue).GetNanoSeconds() &lt;&lt; "ns)");
}
</code></pre>
<p>Next, we replace the perfect clock previously instantiated on n3(SW) in the TAS section with clock instantiation on the various network devices. Note that the clock instantiated on ES1(n0) is a perfect clock (i.e., it corresponds to the simulation time) since it acts as the Grandmaster.</p>
<pre><code class="language-c++">[...]
Ptr&lt;TsnNode&gt; n3 = CreateObject&lt;TsnNode&gt;();
Names::Add("SW", n3);
//Create and add clocks to TsnNodes
Ptr&lt;Clock&gt; c0 = CreateObject&lt;Clock&gt;(); //perfect clock because Grandmaster
n0-&gt;SetMainClock(c0);
Ptr&lt;ConstantDriftClock&gt; c1 = CreateObject&lt;ConstantDriftClock&gt;();
c1-&gt;SetAttribute("InitialOffset", TimeValue(Seconds(20)));
c1-&gt;SetAttribute("DriftRate", DoubleValue(-50));
c1-&gt;SetAttribute("Granularity", TimeValue(NanoSeconds(10)));
n1-&gt;SetMainClock(c1);
Ptr&lt;ConstantDriftClock&gt; c2 = CreateObject&lt;ConstantDriftClock&gt;();
c2-&gt;SetAttribute("InitialOffset", TimeValue(Seconds(3)));
c2-&gt;SetAttribute("DriftRate", DoubleValue(2));
c2-&gt;SetAttribute("Granularity", TimeValue(NanoSeconds(10)));
n2-&gt;SetMainClock(c2);
Ptr&lt;ConstantDriftClock&gt; c3 = CreateObject&lt;ConstantDriftClock&gt;();
c3-&gt;SetAttribute("InitialOffset", TimeValue(Seconds(0.5)));
c3-&gt;SetAttribute("DriftRate", DoubleValue(-25));
c3-&gt;SetAttribute("Granularity", TimeValue(NanoSeconds(10)));
n3-&gt;SetMainClock(c3);
[...]
</code></pre>
<p>Then, we add and configure the gPTP instances on the different nodes. Note that the implementation of gPTP in Eden-sim only supports static configuration of gPTP (i.e. no BTCA).</p>
<pre><code class="language-c++"> [...]
swnet2-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;());
}
Ptr&lt;GPTP&gt; gPTP0 = CreateObject&lt;GPTP&gt;();
gPTP0-&gt;SetNode(n0);
gPTP0-&gt;SetMainClock(c0);
gPTP0-&gt;AddDomain(0);
gPTP0-&gt;AddPort(net0, GPTP::MASTER, 0);
gPTP0-&gt;SetAttribute("SyncInterval", TimeValue(Seconds(0.125))); //This line is not mandatory because 0.125s is the default value
gPTP0-&gt;SetAttribute("PdelayInterval", TimeValue(Seconds(1))); //This line is not mandatory because 1s is the default value
gPTP0-&gt;SetAttribute("Priority", UintegerValue(7));
n0-&gt;AddApplication(gPTP0);
gPTP0-&gt;SetStartTime(Seconds(0));
Ptr&lt;GPTP&gt; gPTP1 = CreateObject&lt;GPTP&gt;();
gPTP1-&gt;SetNode(n1);
gPTP1-&gt;SetMainClock(c1);
gPTP1-&gt;AddDomain(0);
gPTP1-&gt;AddPort(net1, GPTP::SLAVE, 0);
gPTP1-&gt;SetAttribute("Priority", UintegerValue(7));
n1-&gt;AddApplication(gPTP1);
gPTP1-&gt;SetStartTime(Seconds(0));
Ptr&lt;GPTP&gt; gPTP2 = CreateObject&lt;GPTP&gt;();
gPTP2-&gt;SetNode(n2);
gPTP2-&gt;SetMainClock(c2);
gPTP2-&gt;AddDomain(0);
gPTP2-&gt;AddPort(net2, GPTP::SLAVE, 0);
gPTP2-&gt;SetAttribute("Priority", UintegerValue(7));
n2-&gt;AddApplication(gPTP2);
gPTP2-&gt;SetStartTime(Seconds(0));
Ptr&lt;GPTP&gt; gPTP3 = CreateObject&lt;GPTP&gt;();
gPTP3-&gt;SetNode(n3);
gPTP3-&gt;SetMainClock(c3);
gPTP3-&gt;AddDomain(0);
gPTP3-&gt;AddPort(swnet0, GPTP::SLAVE, 0);
gPTP3-&gt;AddPort(swnet1, GPTP::MASTER, 0);
gPTP3-&gt;AddPort(swnet2, GPTP::MASTER, 0);
gPTP3-&gt;SetAttribute("Priority", UintegerValue(7));
n3-&gt;AddApplication(gPTP3);
gPTP3-&gt;SetStartTime(Seconds(0));
</code></pre>
<p>And finally, we add the callbacks.</p>
<pre><code class="language-c++">[...]
net2-&gt;TraceConnectWithoutContext("MacRx", MakeBoundCallback(&amp;MacRxCallback, context));
//Callback to display clock offset after correction
gPTP1-&gt;TraceConnectWithoutContext("ClockAfterCorrection", MakeBoundCallback(&amp;ClockAfterCorrectionCallback, Names::FindName(n1)));
gPTP2-&gt;TraceConnectWithoutContext("ClockAfterCorrection", MakeBoundCallback(&amp;ClockAfterCorrectionCallback, Names::FindName(n2)));
gPTP3-&gt;TraceConnectWithoutContext("ClockAfterCorrection", MakeBoundCallback(&amp;ClockAfterCorrectionCallback, Names::FindName(n3)));
[...]
</code></pre>
<p>When running the simulation, we can observe that gPTP effectively mitigates clock drift thanks to periodic synchronization on SW and ES2. However, we note that there is no gPTP log for ES3. This is due to the TAS configuration, which never opens the FIFO7 gate used by synchronization messages. Of course, such a configuration has no place in a network that is intended to be functional, but in this example it illustrates the impact of the TAS configuration on gPTP packets.</p>
<h2 id="stream-identification"><a class="header" href="#stream-identification">Stream Identification</a></h2>
<p>Before using PSFP or FRER, it is necessary to implement an identification function. In this section, we will use a null Stream identification function on the switch port connected to ES1. This function will then be used in the following two sections to implement PSFP in order to validate the flow contract and to replicate frames using FRER.</p>
<p>Lets start by importing this function.</p>
<pre><code class="language-c++">[...]
#include "ns3/stream-identification-function-null.h"
[...]
</code></pre>
<p>Next, lets create and add the identification function on port swnet0 in input and outfacing mode.</p>
<pre><code class="language-c++">[...]
swnet2-&gt;StartTas();
//Add a stream identification function
Ptr&lt;NullStreamIdentificationFunction&gt; sif0 = CreateObject&lt;NullStreamIdentificationFunction&gt;();
uint16_t StreamHandle = 10;
sif0-&gt;SetAttribute("VlanID", UintegerValue(1));
sif0-&gt;SetAttribute("Address", AddressValue(net2-&gt;GetAddress()));
n3-&gt;AddStreamIdentificationFunction(StreamHandle, sif0, {swnet0}, {}, {}, {});
[...]
</code></pre>
<h2 id="psfp"><a class="header" href="#psfp">PSFP</a></h2>
<p>Now that we have an identification function capable of identifying frames going from ES1 to ES3 with VLAN ID 1, we can set up a PSFP instance to validate compliance with a network usage contract. Currently, the simulator implements the stream filter and the flow meter. They can be added and configured as follows.</p>
<pre><code class="language-c++">[...]
n3-&gt;AddStreamIdentificationFunction(StreamHandle, sif0, {swnet0}, {}, {}, {});
//PSFP configuration
Ptr&lt;StreamFilterInstance&gt; sfi0 = CreateObject&lt;StreamFilterInstance&gt;();
sfi0-&gt;SetAttribute("StreamHandle", IntegerValue(StreamHandle));
sfi0-&gt;SetAttribute("Priority", IntegerValue(-1)); //-1 = wildcard
sfi0-&gt;SetAttribute("MaxSDUSize", UintegerValue(1422));
n3-&gt;AddStreamFilter(sfi0);
Ptr&lt;FlowMeterInstance&gt; fm0 = CreateObject&lt;FlowMeterInstance&gt;();
fm0-&gt;SetAttribute("CIR", DataRateValue(DataRate("20Kb/s")));
fm0-&gt;SetAttribute("CBS", UintegerValue(1400));
fm0-&gt;SetAttribute("DropOnYellow", BooleanValue(true));
fm0-&gt;SetAttribute("MarkAllFramesRedEnable", BooleanValue(false));
uint16_t fmid = n3-&gt;AddFlowMeter(fm0);
sfi0-&gt;AddFlowMeterInstanceId(fmid);
[...]
</code></pre>
<p>After these changes, running the simulation does not produce a different output from previous runs. However, by changing the parameters of the emitting application to increase its bandwidth consumption (e.g., increasing the packet size) or by increasing the idle slope of the CBS, it is possible to observe that packets that do not comply with the contract are never received as they are discarded.</p>
<h2 id="frer"><a class="header" href="#frer">FRER</a></h2>
<p>And finally, lets instantiate FRER. However, the topology we are working with in this chapter does not have multiple paths between ES1 and ES3. So in this section, we will replicate the frames on the output ports of the switch connected to ES2 and ES3 to illustrate the philosophy behind FRER instantiation. We will only detail the replication part. The elimination part is detailed in the example contrib/tsn/examples/tsn-switched-withFRER.cc, which has a topology much more suited to the use of FRER.</p>
<p>Replication with FRER is based on two functions: Sequence Generation Function and Sequence Encode/Decode Function. These two functions are created and configured as follows.</p>
<pre><code class="language-c++">[...]
sfi0-&gt;AddFlowMeterInstanceId(fmid);
//Sequencing : Sequence generation
Ptr&lt;SequenceGenerationFunction&gt; seqf0 = CreateObject&lt;SequenceGenerationFunction&gt;();
seqf0-&gt;SetAttribute("Direction", BooleanValue(false)); //in-facing
seqf0-&gt;SetStreamHandle({StreamHandle});
n3-&gt;AddSequenceGenerationFunction(seqf0);
//Sequence encode
Ptr&lt;SequenceEncodeDecodeFunction&gt; seqEnc0 = CreateObject&lt;SequenceEncodeDecodeFunction&gt;();
seqEnc0-&gt;SetAttribute("Direction", BooleanValue(false)); //in-facing
seqEnc0-&gt;SetAttribute("Active", BooleanValue(true));
seqEnc0-&gt;SetStreamHandle({StreamHandle});
seqEnc0-&gt;SetPort(swnet0);
n3-&gt;AddSequenceEncodeDecodeFunction(seqEnc0);
//Add a forwarding table entry
sw-&gt;AddForwardingTableEntry(Mac48Address::ConvertFrom(net2-&gt;GetAddress()), 1, {swnet1, swnet2});
[...]
</code></pre>
<p>With this configuration, replication is achieved by forwarding to two different ports. This simplifies configuration by not using the FRER splitting function. However, it is necessary to change the configuration of the forwarding table as shown in the previous listing.</p>
<p>In order to validate the correct operation of the replication (i.e., the addition of the R-TAG), modify the callbacks as follows to display the frame size at transmission and reception.</p>
<pre><code class="language-c++">[...]
//A callback to log the pkt emission
static void
MacTxCallback(std::string context, Ptr&lt;const Packet&gt; p)
{
Ptr&lt;Packet&gt; pkt = p-&gt;Copy();
EthernetHeader2 ethHeader;
pkt-&gt;RemoveHeader(ethHeader);
if (ethHeader.GetVid() == 1) {
NS_LOG_INFO((Simulator::Now()).As(Time::S) &lt;&lt; " \t" &lt;&lt; context &lt;&lt; " : Pkt #" &lt;&lt; p-&gt;GetUid() &lt;&lt; "(" &lt;&lt; p-&gt;GetSize() &lt;&lt; "bytes) sent!");
}
}
//A callback to log the pkt reception
static void
MacRxCallback(std::string context, Ptr&lt;const Packet&gt; p)
{
Ptr&lt;Packet&gt; pkt = p-&gt;Copy();
EthernetHeader2 ethHeader;
pkt-&gt;RemoveHeader(ethHeader);
if (ethHeader.GetVid() == 1) {
NS_LOG_INFO((Simulator::Now()).As(Time::S) &lt;&lt; " \t" &lt;&lt; context &lt;&lt; " : Pkt #" &lt;&lt; p-&gt;GetUid() &lt;&lt; "(" &lt;&lt; p-&gt;GetSize() &lt;&lt; "bytes) received!");
}
}
[...]
</code></pre>
<p>And now, when running the simulation script, we observe an increase in frame size of 6 bytes (the size of R-TAG) between transmission and reception, as illustrated below.</p>
<pre><code class="language-console">[...]
+5s ES1:ES1#01 : Pkt #215(1422bytes) sent!
[...]
+7.30743s ES3:ES3#01 : Pkt #215(1428bytes) received!
[...]
</code></pre>
<h2 id="conclusion-and-final-simulation-script"><a class="header" href="#conclusion-and-final-simulation-script">Conclusion and final simulation script</a></h2>
<p>In this section, we have implemented the various TSN mechanisms of Eden-sim.</p>
<p>Note that the examples found in contrib/tsn/examples/ illustrate more complicated configurations and implement different traces to log information about the mechanisms operation. These examples are a good means of further exploring the uses of these TSN mechanisms.</p>
<p>Here is the script at the end of this chapter:</p>
<pre><code class="language-c++">#include "ns3/simulator.h"
#include "ns3/core-module.h"
#include "ns3/node.h"
#include "ns3/drop-tail-queue.h"
#include "ns3/tsn-node.h"
#include "ns3/tsn-net-device.h"
#include "ns3/cbs.h"
#include "ns3/ethernet-channel.h"
#include "ns3/switch-net-device.h"
#include "ns3/ethernet-generator.h"
#include "ns3/clock-constant-drift.h"
#include "ns3/gPTP.h"
#include "ns3/ethernet-header2.h"
#include "ns3/stream-identification-function-null.h"
using namespace ns3;
NS_LOG_COMPONENT_DEFINE("Chapter 3");
//A callback to log the pkt emission
static void
MacTxCallback(std::string context, Ptr&lt;const Packet&gt; p)
{
Ptr&lt;Packet&gt; pkt = p-&gt;Copy();
EthernetHeader2 ethHeader;
pkt-&gt;RemoveHeader(ethHeader);
if (ethHeader.GetVid() == 1) {
NS_LOG_INFO((Simulator::Now()).As(Time::S) &lt;&lt; " \t" &lt;&lt; context &lt;&lt; " : Pkt #" &lt;&lt; p-&gt;GetUid() &lt;&lt; "(" &lt;&lt; p-&gt;GetSize() &lt;&lt; "bytes) sent!");
}
}
//A callback to log the pkt reception
static void
MacRxCallback(std::string context, Ptr&lt;const Packet&gt; p)
{
Ptr&lt;Packet&gt; pkt = p-&gt;Copy();
EthernetHeader2 ethHeader;
pkt-&gt;RemoveHeader(ethHeader);
if (ethHeader.GetVid() == 1) {
NS_LOG_INFO((Simulator::Now()).As(Time::S) &lt;&lt; " \t" &lt;&lt; context &lt;&lt; " : Pkt #" &lt;&lt; p-&gt;GetUid() &lt;&lt; "(" &lt;&lt; p-&gt;GetSize() &lt;&lt; "bytes) received!");
}
}
//A callback to log clock offset after correction
static void
ClockAfterCorrectionCallback(std::string context, Time clockValue)
{
NS_LOG_INFO("[GPTP] At " &lt;&lt; Simulator::Now() &lt;&lt; " on "&lt;&lt; context &lt;&lt; " clock value after correction = " &lt;&lt; clockValue.GetNanoSeconds() &lt;&lt; "ns (error = "&lt;&lt; (Simulator::Now()-clockValue).GetNanoSeconds() &lt;&lt; "ns)");
}
int
main(int argc, char* argv[])
{
//Enable logging
LogComponentEnable("Chapter 3", LOG_LEVEL_INFO);
//Create four nodes
Ptr&lt;TsnNode&gt; n0 = CreateObject&lt;TsnNode&gt;();
Names::Add("ES1", n0);
Ptr&lt;TsnNode&gt; n1 = CreateObject&lt;TsnNode&gt;();
Names::Add("ES2", n1);
Ptr&lt;TsnNode&gt; n2 = CreateObject&lt;TsnNode&gt;();
Names::Add("ES3", n2);
Ptr&lt;TsnNode&gt; n3 = CreateObject&lt;TsnNode&gt;();
Names::Add("SW", n3);
//Create and add clocks to TsnNodes
Ptr&lt;Clock&gt; c0 = CreateObject&lt;Clock&gt;(); //perfect clock because Grandmaster
n0-&gt;SetMainClock(c0);
Ptr&lt;ConstantDriftClock&gt; c1 = CreateObject&lt;ConstantDriftClock&gt;();
c1-&gt;SetAttribute("InitialOffset", TimeValue(Seconds(20)));
c1-&gt;SetAttribute("DriftRate", DoubleValue(-50));
c1-&gt;SetAttribute("Granularity", TimeValue(NanoSeconds(10)));
n1-&gt;SetMainClock(c1);
Ptr&lt;ConstantDriftClock&gt; c2 = CreateObject&lt;ConstantDriftClock&gt;();
c2-&gt;SetAttribute("InitialOffset", TimeValue(Seconds(3)));
c2-&gt;SetAttribute("DriftRate", DoubleValue(2));
c2-&gt;SetAttribute("Granularity", TimeValue(NanoSeconds(10)));
n2-&gt;SetMainClock(c2);
Ptr&lt;ConstantDriftClock&gt; c3 = CreateObject&lt;ConstantDriftClock&gt;();
c3-&gt;SetAttribute("InitialOffset", TimeValue(Seconds(0.5)));
c3-&gt;SetAttribute("DriftRate", DoubleValue(-25));
c3-&gt;SetAttribute("Granularity", TimeValue(NanoSeconds(10)));
n3-&gt;SetMainClock(c3);
//Create and add a netDevice to each end-station node
Ptr&lt;TsnNetDevice&gt; net0 = CreateObject&lt;TsnNetDevice&gt;();
net0-&gt;SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n0-&gt;AddDevice(net0);
Names::Add("ES1#01", net0);
Ptr&lt;TsnNetDevice&gt; net1 = CreateObject&lt;TsnNetDevice&gt;();
net1-&gt;SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n1-&gt;AddDevice(net1);
Names::Add("ES2#01", net1);
Ptr&lt;TsnNetDevice&gt; net2 = CreateObject&lt;TsnNetDevice&gt;();
net2-&gt;SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n2-&gt;AddDevice(net2);
Names::Add("ES3#01", net2);
//Create and add a netDevice to each switch port
Ptr&lt;TsnNetDevice&gt; swnet0 = CreateObject&lt;TsnNetDevice&gt;();
swnet0-&gt;SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n3-&gt;AddDevice(swnet0);
Names::Add("SW#01", swnet0);
Ptr&lt;TsnNetDevice&gt; swnet1 = CreateObject&lt;TsnNetDevice&gt;();
swnet1-&gt;SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n3-&gt;AddDevice(swnet1);
Names::Add("SW#02", swnet1);
Ptr&lt;TsnNetDevice&gt; swnet2 = CreateObject&lt;TsnNetDevice&gt;();
swnet2-&gt;SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n3-&gt;AddDevice(swnet2);
Names::Add("SW#03", swnet2);
//Create Ethernet Channels and connect switch to the end-stations
Ptr&lt;EthernetChannel&gt; channel0 = CreateObject&lt;EthernetChannel&gt;();
channel0-&gt;SetAttribute("Delay", TimeValue(NanoSeconds(50)));
net0-&gt;Attach(channel0);
swnet0-&gt;Attach(channel0);
Ptr&lt;EthernetChannel&gt; channel1 = CreateObject&lt;EthernetChannel&gt;();
channel1-&gt;SetAttribute("Delay", TimeValue(NanoSeconds(75)));
net1-&gt;Attach(channel1);
swnet1-&gt;Attach(channel1);
Ptr&lt;EthernetChannel&gt; channel2 = CreateObject&lt;EthernetChannel&gt;();
channel2-&gt;SetAttribute("Delay", TimeValue(NanoSeconds(100)));
net2-&gt;Attach(channel2);
swnet2-&gt;Attach(channel2);
//Create and add a switch net device to the switch node
Ptr&lt;SwitchNetDevice&gt; sw = CreateObject&lt;SwitchNetDevice&gt;();
sw-&gt;SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(2)));
sw-&gt;SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(5)));
n3-&gt;AddDevice(sw);
sw-&gt;AddSwitchPort(swnet0);
sw-&gt;AddSwitchPort(swnet1);
sw-&gt;AddSwitchPort(swnet2);
//Allocate Mac addresses to the netDevices
net0-&gt;SetAddress(Mac48Address::Allocate());
net1-&gt;SetAddress(Mac48Address::Allocate());
net2-&gt;SetAddress(Mac48Address::Allocate());
sw-&gt;SetAddress(Mac48Address::Allocate());
//Create 8 output port FIFOs for each netDevice.
Ptr&lt;Cbs&gt; cbs = CreateObject&lt;Cbs&gt;();
cbs-&gt;SetTsnNetDevice(net0);
cbs-&gt;SetAttribute("IdleSlope", DataRateValue(DataRate("20Kb/s")));
cbs-&gt;SetAttribute("portTransmitRate", DataRateValue(DataRate("100Mb/s")));
net0-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;()); //FIFO 0
net0-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;(), cbs); //FIFO 1
for (int i=0; i&lt;6; i++){
net0-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;()); //FIFO 0
}
for (int i=0; i&lt;8; i++){
net1-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;());
net2-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;());
swnet0-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;());
swnet1-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;());
swnet2-&gt;SetQueue(CreateObject&lt;DropTailQueue&lt;Packet&gt;&gt;());
}
//Add and configure gPTP
Ptr&lt;GPTP&gt; gPTP0 = CreateObject&lt;GPTP&gt;();
gPTP0-&gt;SetNode(n0);
gPTP0-&gt;SetMainClock(c0);
gPTP0-&gt;AddDomain(0);
gPTP0-&gt;AddPort(net0, GPTP::MASTER, 0);
gPTP0-&gt;SetAttribute("SyncInterval", TimeValue(Seconds(0.125))); //This line is not mandatory because 0.125s is the default value
gPTP0-&gt;SetAttribute("PdelayInterval", TimeValue(Seconds(1))); //This line is not mandatory because 1s is the default value
gPTP0-&gt;SetAttribute("Priority", UintegerValue(7));
n0-&gt;AddApplication(gPTP0);
gPTP0-&gt;SetStartTime(Seconds(0));
Ptr&lt;GPTP&gt; gPTP1 = CreateObject&lt;GPTP&gt;();
gPTP1-&gt;SetNode(n1);
gPTP1-&gt;SetMainClock(c1);
gPTP1-&gt;AddDomain(0);
gPTP1-&gt;AddPort(net1, GPTP::SLAVE, 0);
gPTP1-&gt;SetAttribute("Priority", UintegerValue(7));
n1-&gt;AddApplication(gPTP1);
gPTP1-&gt;SetStartTime(Seconds(0));
Ptr&lt;GPTP&gt; gPTP2 = CreateObject&lt;GPTP&gt;();
gPTP2-&gt;SetNode(n2);
gPTP2-&gt;SetMainClock(c2);
gPTP2-&gt;AddDomain(0);
gPTP2-&gt;AddPort(net2, GPTP::SLAVE, 0);
gPTP2-&gt;SetAttribute("Priority", UintegerValue(7));
n2-&gt;AddApplication(gPTP2);
gPTP2-&gt;SetStartTime(Seconds(0));
Ptr&lt;GPTP&gt; gPTP3 = CreateObject&lt;GPTP&gt;();
gPTP3-&gt;SetNode(n3);
gPTP3-&gt;SetMainClock(c3);
gPTP3-&gt;AddDomain(0);
gPTP3-&gt;AddPort(swnet0, GPTP::SLAVE, 0);
gPTP3-&gt;AddPort(swnet1, GPTP::MASTER, 0);
gPTP3-&gt;AddPort(swnet2, GPTP::MASTER, 0);
gPTP3-&gt;SetAttribute("Priority", UintegerValue(7));
n3-&gt;AddApplication(gPTP3);
gPTP3-&gt;SetStartTime(Seconds(0));
//Configure TAS schedule
swnet2-&gt;AddGclEntry(Time(Seconds(2)), 0); //All gates are close
swnet2-&gt;AddGclEntry(Time(Seconds(3)), 2); //Only the gate of the FIFO 1 is open
swnet2-&gt;StartTas();
//Add a stream identification function
Ptr&lt;NullStreamIdentificationFunction&gt; sif0 = CreateObject&lt;NullStreamIdentificationFunction&gt;();
uint16_t StreamHandle = 10;
sif0-&gt;SetAttribute("VlanID", UintegerValue(1));
sif0-&gt;SetAttribute("Address", AddressValue(net2-&gt;GetAddress()));
n3-&gt;AddStreamIdentificationFunction(StreamHandle, sif0, {swnet0}, {}, {}, {});
//PSFP configuration
Ptr&lt;StreamFilterInstance&gt; sfi0 = CreateObject&lt;StreamFilterInstance&gt;();
sfi0-&gt;SetAttribute("StreamHandle", IntegerValue(StreamHandle));
sfi0-&gt;SetAttribute("Priority", IntegerValue(-1)); //-1 = wildcard
sfi0-&gt;SetAttribute("MaxSDUSize", UintegerValue(1422));
n3-&gt;AddStreamFilter(sfi0);
Ptr&lt;FlowMeterInstance&gt; fm0 = CreateObject&lt;FlowMeterInstance&gt;();
fm0-&gt;SetAttribute("CIR", DataRateValue(DataRate("20Kb/s")));
fm0-&gt;SetAttribute("CBS", UintegerValue(1400));
fm0-&gt;SetAttribute("DropOnYellow", BooleanValue(true));
fm0-&gt;SetAttribute("MarkAllFramesRedEnable", BooleanValue(false));
uint16_t fmid = n3-&gt;AddFlowMeter(fm0);
sfi0-&gt;AddFlowMeterInstanceId(fmid);
//Sequencing : Sequence generation
Ptr&lt;SequenceGenerationFunction&gt; seqf0 = CreateObject&lt;SequenceGenerationFunction&gt;();
seqf0-&gt;SetAttribute("Direction", BooleanValue(false)); //in-facing
seqf0-&gt;SetStreamHandle({StreamHandle});
n3-&gt;AddSequenceGenerationFunction(seqf0);
//Sequence encode
Ptr&lt;SequenceEncodeDecodeFunction&gt; seqEnc0 = CreateObject&lt;SequenceEncodeDecodeFunction&gt;();
seqEnc0-&gt;SetAttribute("Direction", BooleanValue(false)); //in-facing
seqEnc0-&gt;SetAttribute("Active", BooleanValue(true));
seqEnc0-&gt;SetStreamHandle({StreamHandle});
seqEnc0-&gt;SetPort(swnet0);
n3-&gt;AddSequenceEncodeDecodeFunction(seqEnc0);
//Add a forwarding table entry
sw-&gt;AddForwardingTableEntry(Mac48Address::ConvertFrom(net2-&gt;GetAddress()), 1, {swnet1, swnet2});
//Application description
//ES1 -&gt; ES3 with priority 1
Ptr&lt;EthernetGenerator&gt; app0 = CreateObject&lt;EthernetGenerator&gt;();
app0-&gt;Setup(net0);
app0-&gt;SetAttribute("Address", AddressValue(net2-&gt;GetAddress()));
app0-&gt;SetAttribute("BurstSize", UintegerValue(5));
app0-&gt;SetAttribute("PayloadSize", UintegerValue(1400));
app0-&gt;SetAttribute("Period", TimeValue(Seconds(5)));
app0-&gt;SetAttribute("VlanID", UintegerValue(1));
app0-&gt;SetAttribute("PCP", UintegerValue(1));
n0-&gt;AddApplication(app0);
app0-&gt;SetStartTime(Seconds(0));
app0-&gt;SetStopTime(Seconds(10));
//Callback declarations
//Callback to display the packet sent log
std::string context = Names::FindName(n0) + ":" + Names::FindName(net0);
net0-&gt;TraceConnectWithoutContext("MacTx", MakeBoundCallback(&amp;MacTxCallback, context));
//Callback to display the packet received log
context = Names::FindName(n2) + ":" + Names::FindName(net2);
net2-&gt;TraceConnectWithoutContext("MacRx", MakeBoundCallback(&amp;MacRxCallback, context));
//Callback to display clock offset after correction
gPTP1-&gt;TraceConnectWithoutContext("ClockAfterCorrection", MakeBoundCallback(&amp;ClockAfterCorrectionCallback, Names::FindName(n1)));
gPTP2-&gt;TraceConnectWithoutContext("ClockAfterCorrection", MakeBoundCallback(&amp;ClockAfterCorrectionCallback, Names::FindName(n2)));
gPTP3-&gt;TraceConnectWithoutContext("ClockAfterCorrection", MakeBoundCallback(&amp;ClockAfterCorrectionCallback, Names::FindName(n3)));
//Execute the simulation
NS_LOG_INFO("Start of the simulation");
Simulator::Stop(Seconds(10));
Simulator::Run();
Simulator::Destroy();
NS_LOG_INFO("End of the simulation");
return 0;
}
</code></pre>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../getting_stated/network_customization.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M41.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l160 160c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L109.3 256 246.6 118.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-160 160z"/></svg></span>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../getting_stated/network_customization.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M41.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l160 160c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L109.3 256 246.6 118.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-160 160z"/></svg></span>
</a>
</nav>
</div>
<template id=fa-eye><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M288 32c-80.8 0-145.5 36.8-192.6 80.6C48.6 156 17.3 208 2.5 243.7c-3.3 7.9-3.3 16.7 0 24.6C17.3 304 48.6 356 95.4 399.4C142.5 443.2 207.2 480 288 480s145.5-36.8 192.6-80.6c46.8-43.5 78.1-95.4 93-131.1c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C433.5 68.8 368.8 32 288 32zM432 256c0 79.5-64.5 144-144 144s-144-64.5-144-144s64.5-144 144-144s144 64.5 144 144zM288 192c0 35.3-28.7 64-64 64c-11.5 0-22.3-3-31.6-8.4c-.2 2.8-.4 5.5-.4 8.4c0 53 43 96 96 96s96-43 96-96s-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6z"/></svg></span></template>
<template id=fa-eye-slash><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M38.8 5.1C28.4-3.1 13.3-1.2 5.1 9.2S-1.2 34.7 9.2 42.9l592 464c10.4 8.2 25.5 6.3 33.7-4.1s6.3-25.5-4.1-33.7L525.6 386.7c39.6-40.6 66.4-86.1 79.9-118.4c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C465.5 68.8 400.8 32 320 32c-68.2 0-125 26.3-169.3 60.8L38.8 5.1zM223.1 149.5C248.6 126.2 282.7 112 320 112c79.5 0 144 64.5 144 144c0 24.9-6.3 48.3-17.4 68.7L408 294.5c5.2-11.8 8-24.8 8-38.5c0-53-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6c0 10.2-2.4 19.8-6.6 28.3l-90.3-70.8zm223.1 298L373 389.9c-16.4 6.5-34.3 10.1-53 10.1c-79.5 0-144-64.5-144-144c0-6.9 .5-13.6 1.4-20.2L83.1 161.5C60.3 191.2 44 220.8 34.5 243.7c-3.3 7.9-3.3 16.7 0 24.6c14.9 35.7 46.2 87.7 93 131.1C174.5 443.2 239.2 480 320 480c47.8 0 89.9-12.9 126.2-32.5z"/></svg></span></template>
<template id=fa-copy><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M502.6 70.63l-61.25-61.25C435.4 3.371 427.2 0 418.7 0H255.1c-35.35 0-64 28.66-64 64l.0195 256C192 355.4 220.7 384 256 384h192c35.2 0 64-28.8 64-64V93.25C512 84.77 508.6 76.63 502.6 70.63zM464 320c0 8.836-7.164 16-16 16H255.1c-8.838 0-16-7.164-16-16L239.1 64.13c0-8.836 7.164-16 16-16h128L384 96c0 17.67 14.33 32 32 32h47.1V320zM272 448c0 8.836-7.164 16-16 16H63.1c-8.838 0-16-7.164-16-16L47.98 192.1c0-8.836 7.164-16 16-16H160V128H63.99c-35.35 0-64 28.65-64 64l.0098 256C.002 483.3 28.66 512 64 512h192c35.2 0 64-28.8 64-64v-32h-47.1L272 448z"/></svg></span></template>
<template id=fa-play><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M73 39c-14.8-9.1-33.4-9.4-48.5-.9S0 62.6 0 80V432c0 17.4 9.4 33.4 24.5 41.9s33.7 8.1 48.5-.9L361 297c14.3-8.7 23-24.2 23-41s-8.7-32.2-23-41L73 39z"/></svg></span></template>
<template id=fa-clock-rotate-left><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M75 75L41 41C25.9 25.9 0 36.6 0 57.9V168c0 13.3 10.7 24 24 24H134.1c21.4 0 32.1-25.9 17-41l-30.8-30.8C155 85.5 203 64 256 64c106 0 192 86 192 192s-86 192-192 192c-40.8 0-78.6-12.7-109.7-34.4c-14.5-10.1-34.4-6.6-44.6 7.9s-6.6 34.4 7.9 44.6C151.2 495 201.7 512 256 512c141.4 0 256-114.6 256-256S397.4 0 256 0C185.3 0 121.3 28.7 75 75zm181 53c-13.3 0-24 10.7-24 24V256c0 6.4 2.5 12.5 7 17l72 72c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-65-65V152c0-13.3-10.7-24-24-24z"/></svg></span></template>
<!-- Livereload script (if served using the cli tool) -->
<script>
const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
const wsAddress = wsProtocol + "//" + location.host + "/" + "__livereload";
const socket = new WebSocket(wsAddress);
socket.onmessage = function (event) {
if (event.data === "reload") {
socket.close();
location.reload();
}
};
window.onbeforeunload = function() {
socket.close();
}
</script>
<script>
window.playground_copyable = true;
</script>
<script src="../elasticlunr-ef4e11c1.min.js"></script>
<script src="../mark-09e88c2c.min.js"></script>
<script src="../searcher-c2a407aa.js"></script>
<script src="../clipboard-1626706a.min.js"></script>
<script src="../highlight-abc7f01d.js"></script>
<script src="../book-a0b12cfe.js"></script>
<!-- Custom JS scripts -->
</div>
</body>
</html>

View File

@@ -0,0 +1,83 @@
/*
* An increased contrast highlighting scheme loosely based on the
* "Base16 Atelier Dune Light" theme by Bram de Haan
* (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/dune)
* Original Base16 color scheme by Chris Kempson
* (https://github.com/chriskempson/base16)
*/
/* Comment */
.hljs-comment,
.hljs-quote {
color: #575757;
}
/* Red */
.hljs-variable,
.hljs-template-variable,
.hljs-attribute,
.hljs-attr,
.hljs-tag,
.hljs-name,
.hljs-regexp,
.hljs-link,
.hljs-name,
.hljs-selector-id,
.hljs-selector-class {
color: #d70025;
}
/* Orange */
.hljs-number,
.hljs-meta,
.hljs-built_in,
.hljs-builtin-name,
.hljs-literal,
.hljs-type,
.hljs-params {
color: #b21e00;
}
/* Green */
.hljs-string,
.hljs-symbol,
.hljs-bullet {
color: #008200;
}
/* Blue */
.hljs-title,
.hljs-section {
color: #0030f2;
}
/* Purple */
.hljs-keyword,
.hljs-selector-tag {
color: #9d00ec;
}
.hljs {
display: block;
overflow-x: auto;
background: #f6f7f6;
color: #000;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}
.hljs-addition {
color: #22863a;
background-color: #f0fff4;
}
.hljs-deletion {
color: #b31d28;
background-color: #ffeef0;
}

File diff suppressed because one or more lines are too long

259
userGuide/book/index.html Normal file
View File

@@ -0,0 +1,259 @@
<!DOCTYPE HTML>
<html lang="en" class="light sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Introduction - Eden-sim - User Guide</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-de23e50b.svg">
<link rel="shortcut icon" href="favicon-8114d1fc.png">
<link rel="stylesheet" href="css/variables-8adf115d.css">
<link rel="stylesheet" href="css/general-2459343d.css">
<link rel="stylesheet" href="css/chrome-ae938929.css">
<link rel="stylesheet" href="css/print-9e4910d8.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="fonts/fonts-9644e21d.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" id="mdbook-highlight-css" href="highlight-493f70e1.css">
<link rel="stylesheet" id="mdbook-tomorrow-night-css" href="tomorrow-night-4c0ae647.css">
<link rel="stylesheet" id="mdbook-ayu-highlight-css" href="ayu-highlight-3fdfc3ac.css">
<!-- Custom theme stylesheets -->
<!-- Provide site root and default themes to javascript -->
<script>
const path_to_root = "";
const default_light_theme = "light";
const default_dark_theme = "navy";
window.path_to_searchindex_js = "searchindex-43c2d326.js";
</script>
<!-- Start loading toc.js asap -->
<script src="toc-81bc4348.js"></script>
</head>
<body>
<div id="mdbook-help-container">
<div id="mdbook-help-popup">
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
<div>
<p>Press <kbd></kbd> or <kbd></kbd> to navigate between chapters</p>
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
<p>Press <kbd>?</kbd> to show this help</p>
<p>Press <kbd>Esc</kbd> to hide this help</p>
</div>
</div>
</div>
<div id="mdbook-body-container">
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
let theme = localStorage.getItem('mdbook-theme');
let 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>
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
let theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
const html = document.documentElement;
html.classList.remove('light')
html.classList.add(theme);
html.classList.add("js");
</script>
<input type="checkbox" id="mdbook-sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
let sidebar = null;
const sidebar_toggle = document.getElementById("mdbook-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 = false;
}
if (sidebar === 'visible') {
sidebar_toggle.checked = true;
} else {
html.classList.remove('sidebar-visible');
}
</script>
<nav id="mdbook-sidebar" class="sidebar" aria-label="Table of contents">
<!-- populated by js -->
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
<noscript>
<iframe class="sidebar-iframe-outer" src="toc.html"></iframe>
</noscript>
<div id="mdbook-sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<div id="mdbook-page-wrapper" class="page-wrapper">
<div class="page">
<div id="mdbook-menu-bar-hover-placeholder"></div>
<div id="mdbook-menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="mdbook-sidebar-toggle" class="icon-button" for="mdbook-sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="mdbook-sidebar">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M0 96C0 78.3 14.3 64 32 64H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H32C14.3 128 0 113.7 0 96zM0 256c0-17.7 14.3-32 32-32H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H32c-17.7 0-32-14.3-32-32zM448 416c0 17.7-14.3 32-32 32H32c-17.7 0-32-14.3-32-32s14.3-32 32-32H416c17.7 0 32 14.3 32 32z"/></svg></span>
</label>
<button id="mdbook-theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="mdbook-theme-list">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M371.3 367.1c27.3-3.9 51.9-19.4 67.2-42.9L600.2 74.1c12.6-19.5 9.4-45.3-7.6-61.2S549.7-4.4 531.1 9.6L294.4 187.2c-24 18-38.2 46.1-38.4 76.1L371.3 367.1zm-19.6 25.4l-116-104.4C175.9 290.3 128 339.6 128 400c0 3.9 .2 7.8 .6 11.6c1.8 17.5-10.2 36.4-27.8 36.4H96c-17.7 0-32 14.3-32 32s14.3 32 32 32H240c61.9 0 112-50.1 112-112c0-2.5-.1-5-.2-7.5z"/></svg></span>
</button>
<ul id="mdbook-theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-default_theme">Auto</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-ayu">Ayu</button></li>
</ul>
<button id="mdbook-search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="mdbook-searchbar">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352c79.5 0 144-64.5 144-144s-64.5-144-144-144S64 128.5 64 208s64.5 144 144 144z"/></svg></span>
</button>
</div>
<h1 class="menu-title">Eden-sim - User Guide</h1>
<div class="right-buttons">
<a href="print.html" title="Print this book" aria-label="Print this book">
<span class=fa-svg id="print-button"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M128 0C92.7 0 64 28.7 64 64v96h64V64H354.7L384 93.3V160h64V93.3c0-17-6.7-33.3-18.7-45.3L400 18.7C388 6.7 371.7 0 354.7 0H128zM384 352v32 64H128V384 368 352H384zm64 32h32c17.7 0 32-14.3 32-32V256c0-35.3-28.7-64-64-64H64c-35.3 0-64 28.7-64 64v96c0 17.7 14.3 32 32 32H64v64c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V384zm-16-88c-13.3 0-24-10.7-24-24s10.7-24 24-24s24 10.7 24 24s-10.7 24-24 24z"/></svg></span>
</a>
</div>
</div>
<div id="mdbook-search-wrapper" class="hidden">
<form id="mdbook-searchbar-outer" class="searchbar-outer">
<div class="search-wrapper">
<input type="search" id="mdbook-searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="mdbook-searchresults-outer" aria-describedby="searchresults-header">
<div class="spinner-wrapper">
<span class=fa-svg id="fa-spin"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M304 48c0-26.5-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48s48-21.5 48-48zm0 416c0-26.5-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48s48-21.5 48-48zM48 304c26.5 0 48-21.5 48-48s-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48zm464-48c0-26.5-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48s48-21.5 48-48zM142.9 437c18.7-18.7 18.7-49.1 0-67.9s-49.1-18.7-67.9 0s-18.7 49.1 0 67.9s49.1 18.7 67.9 0zm0-294.2c18.7-18.7 18.7-49.1 0-67.9S93.7 56.2 75 75s-18.7 49.1 0 67.9s49.1 18.7 67.9 0zM369.1 437c18.7 18.7 49.1 18.7 67.9 0s18.7-49.1 0-67.9s-49.1-18.7-67.9 0s-18.7 49.1 0 67.9z"/></svg></span>
</div>
</div>
</form>
<div id="mdbook-searchresults-outer" class="searchresults-outer hidden">
<div id="mdbook-searchresults-header" class="searchresults-header"></div>
<ul id="mdbook-searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('mdbook-sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('mdbook-sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#mdbook-sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="mdbook-content" class="content">
<main>
<h1 id="introduction"><a class="header" href="#introduction">Introduction</a></h1>
<p>Eden-sim is a ns-3 simulation library for embedded TSN networks.</p>
<p>This book is a user guide designed to assist in the creation of simulation scripts using Eden-sim. It is organised as follows:</p>
<ul>
<li>Getting started part to introduce the fundamental ideas of Eden-sim</li>
<li>Advanced uses part for complex projects</li>
</ul>
<p>Please note that in addition to the examples presented in this guide, example simulation scripts are also available in the following folders:</p>
<ul>
<li>contrib/ethernet/examples</li>
<li>contrib/real-device/examples</li>
<li>contrib/trace/examples</li>
<li>contrib/traffic-generator/examples</li>
<li>contrib/tsn/examples</li>
</ul>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="next prefetch" href="prerequisites.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M278.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-160 160c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L210.7 256 73.4 118.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l160 160z"/></svg></span>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="next prefetch" href="prerequisites.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M278.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-160 160c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L210.7 256 73.4 118.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l160 160z"/></svg></span>
</a>
</nav>
</div>
<template id=fa-eye><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M288 32c-80.8 0-145.5 36.8-192.6 80.6C48.6 156 17.3 208 2.5 243.7c-3.3 7.9-3.3 16.7 0 24.6C17.3 304 48.6 356 95.4 399.4C142.5 443.2 207.2 480 288 480s145.5-36.8 192.6-80.6c46.8-43.5 78.1-95.4 93-131.1c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C433.5 68.8 368.8 32 288 32zM432 256c0 79.5-64.5 144-144 144s-144-64.5-144-144s64.5-144 144-144s144 64.5 144 144zM288 192c0 35.3-28.7 64-64 64c-11.5 0-22.3-3-31.6-8.4c-.2 2.8-.4 5.5-.4 8.4c0 53 43 96 96 96s96-43 96-96s-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6z"/></svg></span></template>
<template id=fa-eye-slash><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M38.8 5.1C28.4-3.1 13.3-1.2 5.1 9.2S-1.2 34.7 9.2 42.9l592 464c10.4 8.2 25.5 6.3 33.7-4.1s6.3-25.5-4.1-33.7L525.6 386.7c39.6-40.6 66.4-86.1 79.9-118.4c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C465.5 68.8 400.8 32 320 32c-68.2 0-125 26.3-169.3 60.8L38.8 5.1zM223.1 149.5C248.6 126.2 282.7 112 320 112c79.5 0 144 64.5 144 144c0 24.9-6.3 48.3-17.4 68.7L408 294.5c5.2-11.8 8-24.8 8-38.5c0-53-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6c0 10.2-2.4 19.8-6.6 28.3l-90.3-70.8zm223.1 298L373 389.9c-16.4 6.5-34.3 10.1-53 10.1c-79.5 0-144-64.5-144-144c0-6.9 .5-13.6 1.4-20.2L83.1 161.5C60.3 191.2 44 220.8 34.5 243.7c-3.3 7.9-3.3 16.7 0 24.6c14.9 35.7 46.2 87.7 93 131.1C174.5 443.2 239.2 480 320 480c47.8 0 89.9-12.9 126.2-32.5z"/></svg></span></template>
<template id=fa-copy><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M502.6 70.63l-61.25-61.25C435.4 3.371 427.2 0 418.7 0H255.1c-35.35 0-64 28.66-64 64l.0195 256C192 355.4 220.7 384 256 384h192c35.2 0 64-28.8 64-64V93.25C512 84.77 508.6 76.63 502.6 70.63zM464 320c0 8.836-7.164 16-16 16H255.1c-8.838 0-16-7.164-16-16L239.1 64.13c0-8.836 7.164-16 16-16h128L384 96c0 17.67 14.33 32 32 32h47.1V320zM272 448c0 8.836-7.164 16-16 16H63.1c-8.838 0-16-7.164-16-16L47.98 192.1c0-8.836 7.164-16 16-16H160V128H63.99c-35.35 0-64 28.65-64 64l.0098 256C.002 483.3 28.66 512 64 512h192c35.2 0 64-28.8 64-64v-32h-47.1L272 448z"/></svg></span></template>
<template id=fa-play><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M73 39c-14.8-9.1-33.4-9.4-48.5-.9S0 62.6 0 80V432c0 17.4 9.4 33.4 24.5 41.9s33.7 8.1 48.5-.9L361 297c14.3-8.7 23-24.2 23-41s-8.7-32.2-23-41L73 39z"/></svg></span></template>
<template id=fa-clock-rotate-left><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M75 75L41 41C25.9 25.9 0 36.6 0 57.9V168c0 13.3 10.7 24 24 24H134.1c21.4 0 32.1-25.9 17-41l-30.8-30.8C155 85.5 203 64 256 64c106 0 192 86 192 192s-86 192-192 192c-40.8 0-78.6-12.7-109.7-34.4c-14.5-10.1-34.4-6.6-44.6 7.9s-6.6 34.4 7.9 44.6C151.2 495 201.7 512 256 512c141.4 0 256-114.6 256-256S397.4 0 256 0C185.3 0 121.3 28.7 75 75zm181 53c-13.3 0-24 10.7-24 24V256c0 6.4 2.5 12.5 7 17l72 72c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-65-65V152c0-13.3-10.7-24-24-24z"/></svg></span></template>
<!-- Livereload script (if served using the cli tool) -->
<script>
const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
const wsAddress = wsProtocol + "//" + location.host + "/" + "__livereload";
const socket = new WebSocket(wsAddress);
socket.onmessage = function (event) {
if (event.data === "reload") {
socket.close();
location.reload();
}
};
window.onbeforeunload = function() {
socket.close();
}
</script>
<script>
window.playground_copyable = true;
</script>
<script src="elasticlunr-ef4e11c1.min.js"></script>
<script src="mark-09e88c2c.min.js"></script>
<script src="searcher-c2a407aa.js"></script>
<script src="clipboard-1626706a.min.js"></script>
<script src="highlight-abc7f01d.js"></script>
<script src="book-a0b12cfe.js"></script>
<!-- Custom JS scripts -->
</div>
</body>
</html>

View File

@@ -0,0 +1,259 @@
<!DOCTYPE HTML>
<html lang="en" class="light sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Introduction - Eden-sim - User Guide</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-de23e50b.svg">
<link rel="shortcut icon" href="favicon-8114d1fc.png">
<link rel="stylesheet" href="css/variables-8adf115d.css">
<link rel="stylesheet" href="css/general-2459343d.css">
<link rel="stylesheet" href="css/chrome-ae938929.css">
<link rel="stylesheet" href="css/print-9e4910d8.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="fonts/fonts-9644e21d.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" id="mdbook-highlight-css" href="highlight-493f70e1.css">
<link rel="stylesheet" id="mdbook-tomorrow-night-css" href="tomorrow-night-4c0ae647.css">
<link rel="stylesheet" id="mdbook-ayu-highlight-css" href="ayu-highlight-3fdfc3ac.css">
<!-- Custom theme stylesheets -->
<!-- Provide site root and default themes to javascript -->
<script>
const path_to_root = "";
const default_light_theme = "light";
const default_dark_theme = "navy";
window.path_to_searchindex_js = "searchindex-43c2d326.js";
</script>
<!-- Start loading toc.js asap -->
<script src="toc-81bc4348.js"></script>
</head>
<body>
<div id="mdbook-help-container">
<div id="mdbook-help-popup">
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
<div>
<p>Press <kbd></kbd> or <kbd></kbd> to navigate between chapters</p>
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
<p>Press <kbd>?</kbd> to show this help</p>
<p>Press <kbd>Esc</kbd> to hide this help</p>
</div>
</div>
</div>
<div id="mdbook-body-container">
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
let theme = localStorage.getItem('mdbook-theme');
let 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>
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
let theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
const html = document.documentElement;
html.classList.remove('light')
html.classList.add(theme);
html.classList.add("js");
</script>
<input type="checkbox" id="mdbook-sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
let sidebar = null;
const sidebar_toggle = document.getElementById("mdbook-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 = false;
}
if (sidebar === 'visible') {
sidebar_toggle.checked = true;
} else {
html.classList.remove('sidebar-visible');
}
</script>
<nav id="mdbook-sidebar" class="sidebar" aria-label="Table of contents">
<!-- populated by js -->
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
<noscript>
<iframe class="sidebar-iframe-outer" src="toc.html"></iframe>
</noscript>
<div id="mdbook-sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<div id="mdbook-page-wrapper" class="page-wrapper">
<div class="page">
<div id="mdbook-menu-bar-hover-placeholder"></div>
<div id="mdbook-menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="mdbook-sidebar-toggle" class="icon-button" for="mdbook-sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="mdbook-sidebar">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M0 96C0 78.3 14.3 64 32 64H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H32C14.3 128 0 113.7 0 96zM0 256c0-17.7 14.3-32 32-32H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H32c-17.7 0-32-14.3-32-32zM448 416c0 17.7-14.3 32-32 32H32c-17.7 0-32-14.3-32-32s14.3-32 32-32H416c17.7 0 32 14.3 32 32z"/></svg></span>
</label>
<button id="mdbook-theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="mdbook-theme-list">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M371.3 367.1c27.3-3.9 51.9-19.4 67.2-42.9L600.2 74.1c12.6-19.5 9.4-45.3-7.6-61.2S549.7-4.4 531.1 9.6L294.4 187.2c-24 18-38.2 46.1-38.4 76.1L371.3 367.1zm-19.6 25.4l-116-104.4C175.9 290.3 128 339.6 128 400c0 3.9 .2 7.8 .6 11.6c1.8 17.5-10.2 36.4-27.8 36.4H96c-17.7 0-32 14.3-32 32s14.3 32 32 32H240c61.9 0 112-50.1 112-112c0-2.5-.1-5-.2-7.5z"/></svg></span>
</button>
<ul id="mdbook-theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-default_theme">Auto</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-ayu">Ayu</button></li>
</ul>
<button id="mdbook-search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="mdbook-searchbar">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352c79.5 0 144-64.5 144-144s-64.5-144-144-144S64 128.5 64 208s64.5 144 144 144z"/></svg></span>
</button>
</div>
<h1 class="menu-title">Eden-sim - User Guide</h1>
<div class="right-buttons">
<a href="print.html" title="Print this book" aria-label="Print this book">
<span class=fa-svg id="print-button"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M128 0C92.7 0 64 28.7 64 64v96h64V64H354.7L384 93.3V160h64V93.3c0-17-6.7-33.3-18.7-45.3L400 18.7C388 6.7 371.7 0 354.7 0H128zM384 352v32 64H128V384 368 352H384zm64 32h32c17.7 0 32-14.3 32-32V256c0-35.3-28.7-64-64-64H64c-35.3 0-64 28.7-64 64v96c0 17.7 14.3 32 32 32H64v64c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V384zm-16-88c-13.3 0-24-10.7-24-24s10.7-24 24-24s24 10.7 24 24s-10.7 24-24 24z"/></svg></span>
</a>
</div>
</div>
<div id="mdbook-search-wrapper" class="hidden">
<form id="mdbook-searchbar-outer" class="searchbar-outer">
<div class="search-wrapper">
<input type="search" id="mdbook-searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="mdbook-searchresults-outer" aria-describedby="searchresults-header">
<div class="spinner-wrapper">
<span class=fa-svg id="fa-spin"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M304 48c0-26.5-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48s48-21.5 48-48zm0 416c0-26.5-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48s48-21.5 48-48zM48 304c26.5 0 48-21.5 48-48s-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48zm464-48c0-26.5-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48s48-21.5 48-48zM142.9 437c18.7-18.7 18.7-49.1 0-67.9s-49.1-18.7-67.9 0s-18.7 49.1 0 67.9s49.1 18.7 67.9 0zm0-294.2c18.7-18.7 18.7-49.1 0-67.9S93.7 56.2 75 75s-18.7 49.1 0 67.9s49.1 18.7 67.9 0zM369.1 437c18.7 18.7 49.1 18.7 67.9 0s18.7-49.1 0-67.9s-49.1-18.7-67.9 0s-18.7 49.1 0 67.9z"/></svg></span>
</div>
</div>
</form>
<div id="mdbook-searchresults-outer" class="searchresults-outer hidden">
<div id="mdbook-searchresults-header" class="searchresults-header"></div>
<ul id="mdbook-searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('mdbook-sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('mdbook-sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#mdbook-sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="mdbook-content" class="content">
<main>
<h1 id="introduction"><a class="header" href="#introduction">Introduction</a></h1>
<p>Eden-sim is a ns-3 simulation library for embedded TSN networks.</p>
<p>This book is a user guide designed to assist in the creation of simulation scripts using Eden-sim. It is organised as follows:</p>
<ul>
<li>Getting started part to introduce the fundamental ideas of Eden-sim</li>
<li>Advanced uses part for complex projects</li>
</ul>
<p>Please note that in addition to the examples presented in this guide, example simulation scripts are also available in the following folders:</p>
<ul>
<li>contrib/ethernet/examples</li>
<li>contrib/real-device/examples</li>
<li>contrib/trace/examples</li>
<li>contrib/traffic-generator/examples</li>
<li>contrib/tsn/examples</li>
</ul>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="next prefetch" href="prerequisites.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M278.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-160 160c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L210.7 256 73.4 118.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l160 160z"/></svg></span>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="next prefetch" href="prerequisites.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M278.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-160 160c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L210.7 256 73.4 118.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l160 160z"/></svg></span>
</a>
</nav>
</div>
<template id=fa-eye><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M288 32c-80.8 0-145.5 36.8-192.6 80.6C48.6 156 17.3 208 2.5 243.7c-3.3 7.9-3.3 16.7 0 24.6C17.3 304 48.6 356 95.4 399.4C142.5 443.2 207.2 480 288 480s145.5-36.8 192.6-80.6c46.8-43.5 78.1-95.4 93-131.1c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C433.5 68.8 368.8 32 288 32zM432 256c0 79.5-64.5 144-144 144s-144-64.5-144-144s64.5-144 144-144s144 64.5 144 144zM288 192c0 35.3-28.7 64-64 64c-11.5 0-22.3-3-31.6-8.4c-.2 2.8-.4 5.5-.4 8.4c0 53 43 96 96 96s96-43 96-96s-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6z"/></svg></span></template>
<template id=fa-eye-slash><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M38.8 5.1C28.4-3.1 13.3-1.2 5.1 9.2S-1.2 34.7 9.2 42.9l592 464c10.4 8.2 25.5 6.3 33.7-4.1s6.3-25.5-4.1-33.7L525.6 386.7c39.6-40.6 66.4-86.1 79.9-118.4c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C465.5 68.8 400.8 32 320 32c-68.2 0-125 26.3-169.3 60.8L38.8 5.1zM223.1 149.5C248.6 126.2 282.7 112 320 112c79.5 0 144 64.5 144 144c0 24.9-6.3 48.3-17.4 68.7L408 294.5c5.2-11.8 8-24.8 8-38.5c0-53-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6c0 10.2-2.4 19.8-6.6 28.3l-90.3-70.8zm223.1 298L373 389.9c-16.4 6.5-34.3 10.1-53 10.1c-79.5 0-144-64.5-144-144c0-6.9 .5-13.6 1.4-20.2L83.1 161.5C60.3 191.2 44 220.8 34.5 243.7c-3.3 7.9-3.3 16.7 0 24.6c14.9 35.7 46.2 87.7 93 131.1C174.5 443.2 239.2 480 320 480c47.8 0 89.9-12.9 126.2-32.5z"/></svg></span></template>
<template id=fa-copy><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M502.6 70.63l-61.25-61.25C435.4 3.371 427.2 0 418.7 0H255.1c-35.35 0-64 28.66-64 64l.0195 256C192 355.4 220.7 384 256 384h192c35.2 0 64-28.8 64-64V93.25C512 84.77 508.6 76.63 502.6 70.63zM464 320c0 8.836-7.164 16-16 16H255.1c-8.838 0-16-7.164-16-16L239.1 64.13c0-8.836 7.164-16 16-16h128L384 96c0 17.67 14.33 32 32 32h47.1V320zM272 448c0 8.836-7.164 16-16 16H63.1c-8.838 0-16-7.164-16-16L47.98 192.1c0-8.836 7.164-16 16-16H160V128H63.99c-35.35 0-64 28.65-64 64l.0098 256C.002 483.3 28.66 512 64 512h192c35.2 0 64-28.8 64-64v-32h-47.1L272 448z"/></svg></span></template>
<template id=fa-play><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M73 39c-14.8-9.1-33.4-9.4-48.5-.9S0 62.6 0 80V432c0 17.4 9.4 33.4 24.5 41.9s33.7 8.1 48.5-.9L361 297c14.3-8.7 23-24.2 23-41s-8.7-32.2-23-41L73 39z"/></svg></span></template>
<template id=fa-clock-rotate-left><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M75 75L41 41C25.9 25.9 0 36.6 0 57.9V168c0 13.3 10.7 24 24 24H134.1c21.4 0 32.1-25.9 17-41l-30.8-30.8C155 85.5 203 64 256 64c106 0 192 86 192 192s-86 192-192 192c-40.8 0-78.6-12.7-109.7-34.4c-14.5-10.1-34.4-6.6-44.6 7.9s-6.6 34.4 7.9 44.6C151.2 495 201.7 512 256 512c141.4 0 256-114.6 256-256S397.4 0 256 0C185.3 0 121.3 28.7 75 75zm181 53c-13.3 0-24 10.7-24 24V256c0 6.4 2.5 12.5 7 17l72 72c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-65-65V152c0-13.3-10.7-24-24-24z"/></svg></span></template>
<!-- Livereload script (if served using the cli tool) -->
<script>
const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
const wsAddress = wsProtocol + "//" + location.host + "/" + "__livereload";
const socket = new WebSocket(wsAddress);
socket.onmessage = function (event) {
if (event.data === "reload") {
socket.close();
location.reload();
}
};
window.onbeforeunload = function() {
socket.close();
}
</script>
<script>
window.playground_copyable = true;
</script>
<script src="elasticlunr-ef4e11c1.min.js"></script>
<script src="mark-09e88c2c.min.js"></script>
<script src="searcher-c2a407aa.js"></script>
<script src="clipboard-1626706a.min.js"></script>
<script src="highlight-abc7f01d.js"></script>
<script src="book-a0b12cfe.js"></script>
<!-- Custom JS scripts -->
</div>
</body>
</html>

7
userGuide/book/mark-09e88c2c.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,252 @@
<!DOCTYPE HTML>
<html lang="en" class="light sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Prerequisites - Eden-sim - User Guide</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-de23e50b.svg">
<link rel="shortcut icon" href="favicon-8114d1fc.png">
<link rel="stylesheet" href="css/variables-8adf115d.css">
<link rel="stylesheet" href="css/general-2459343d.css">
<link rel="stylesheet" href="css/chrome-ae938929.css">
<link rel="stylesheet" href="css/print-9e4910d8.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="fonts/fonts-9644e21d.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" id="mdbook-highlight-css" href="highlight-493f70e1.css">
<link rel="stylesheet" id="mdbook-tomorrow-night-css" href="tomorrow-night-4c0ae647.css">
<link rel="stylesheet" id="mdbook-ayu-highlight-css" href="ayu-highlight-3fdfc3ac.css">
<!-- Custom theme stylesheets -->
<!-- Provide site root and default themes to javascript -->
<script>
const path_to_root = "";
const default_light_theme = "light";
const default_dark_theme = "navy";
window.path_to_searchindex_js = "searchindex-43c2d326.js";
</script>
<!-- Start loading toc.js asap -->
<script src="toc-81bc4348.js"></script>
</head>
<body>
<div id="mdbook-help-container">
<div id="mdbook-help-popup">
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
<div>
<p>Press <kbd></kbd> or <kbd></kbd> to navigate between chapters</p>
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
<p>Press <kbd>?</kbd> to show this help</p>
<p>Press <kbd>Esc</kbd> to hide this help</p>
</div>
</div>
</div>
<div id="mdbook-body-container">
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
let theme = localStorage.getItem('mdbook-theme');
let 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>
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
let theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
const html = document.documentElement;
html.classList.remove('light')
html.classList.add(theme);
html.classList.add("js");
</script>
<input type="checkbox" id="mdbook-sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
let sidebar = null;
const sidebar_toggle = document.getElementById("mdbook-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 = false;
}
if (sidebar === 'visible') {
sidebar_toggle.checked = true;
} else {
html.classList.remove('sidebar-visible');
}
</script>
<nav id="mdbook-sidebar" class="sidebar" aria-label="Table of contents">
<!-- populated by js -->
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
<noscript>
<iframe class="sidebar-iframe-outer" src="toc.html"></iframe>
</noscript>
<div id="mdbook-sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<div id="mdbook-page-wrapper" class="page-wrapper">
<div class="page">
<div id="mdbook-menu-bar-hover-placeholder"></div>
<div id="mdbook-menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="mdbook-sidebar-toggle" class="icon-button" for="mdbook-sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="mdbook-sidebar">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M0 96C0 78.3 14.3 64 32 64H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H32C14.3 128 0 113.7 0 96zM0 256c0-17.7 14.3-32 32-32H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H32c-17.7 0-32-14.3-32-32zM448 416c0 17.7-14.3 32-32 32H32c-17.7 0-32-14.3-32-32s14.3-32 32-32H416c17.7 0 32 14.3 32 32z"/></svg></span>
</label>
<button id="mdbook-theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="mdbook-theme-list">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M371.3 367.1c27.3-3.9 51.9-19.4 67.2-42.9L600.2 74.1c12.6-19.5 9.4-45.3-7.6-61.2S549.7-4.4 531.1 9.6L294.4 187.2c-24 18-38.2 46.1-38.4 76.1L371.3 367.1zm-19.6 25.4l-116-104.4C175.9 290.3 128 339.6 128 400c0 3.9 .2 7.8 .6 11.6c1.8 17.5-10.2 36.4-27.8 36.4H96c-17.7 0-32 14.3-32 32s14.3 32 32 32H240c61.9 0 112-50.1 112-112c0-2.5-.1-5-.2-7.5z"/></svg></span>
</button>
<ul id="mdbook-theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-default_theme">Auto</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="mdbook-theme-ayu">Ayu</button></li>
</ul>
<button id="mdbook-search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="mdbook-searchbar">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352c79.5 0 144-64.5 144-144s-64.5-144-144-144S64 128.5 64 208s64.5 144 144 144z"/></svg></span>
</button>
</div>
<h1 class="menu-title">Eden-sim - User Guide</h1>
<div class="right-buttons">
<a href="print.html" title="Print this book" aria-label="Print this book">
<span class=fa-svg id="print-button"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M128 0C92.7 0 64 28.7 64 64v96h64V64H354.7L384 93.3V160h64V93.3c0-17-6.7-33.3-18.7-45.3L400 18.7C388 6.7 371.7 0 354.7 0H128zM384 352v32 64H128V384 368 352H384zm64 32h32c17.7 0 32-14.3 32-32V256c0-35.3-28.7-64-64-64H64c-35.3 0-64 28.7-64 64v96c0 17.7 14.3 32 32 32H64v64c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V384zm-16-88c-13.3 0-24-10.7-24-24s10.7-24 24-24s24 10.7 24 24s-10.7 24-24 24z"/></svg></span>
</a>
</div>
</div>
<div id="mdbook-search-wrapper" class="hidden">
<form id="mdbook-searchbar-outer" class="searchbar-outer">
<div class="search-wrapper">
<input type="search" id="mdbook-searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="mdbook-searchresults-outer" aria-describedby="searchresults-header">
<div class="spinner-wrapper">
<span class=fa-svg id="fa-spin"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M304 48c0-26.5-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48s48-21.5 48-48zm0 416c0-26.5-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48s48-21.5 48-48zM48 304c26.5 0 48-21.5 48-48s-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48zm464-48c0-26.5-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48s48-21.5 48-48zM142.9 437c18.7-18.7 18.7-49.1 0-67.9s-49.1-18.7-67.9 0s-18.7 49.1 0 67.9s49.1 18.7 67.9 0zm0-294.2c18.7-18.7 18.7-49.1 0-67.9S93.7 56.2 75 75s-18.7 49.1 0 67.9s49.1 18.7 67.9 0zM369.1 437c18.7 18.7 49.1 18.7 67.9 0s18.7-49.1 0-67.9s-49.1-18.7-67.9 0s-18.7 49.1 0 67.9z"/></svg></span>
</div>
</div>
</form>
<div id="mdbook-searchresults-outer" class="searchresults-outer hidden">
<div id="mdbook-searchresults-header" class="searchresults-header"></div>
<ul id="mdbook-searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('mdbook-sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('mdbook-sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#mdbook-sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="mdbook-content" class="content">
<main>
<h1 id="prerequisites"><a class="header" href="#prerequisites">Prerequisites</a></h1>
<p>To put this guide into practice, you only need to have ns-3 and Eden-sim installed. The installation procedure for these two tools is described in Eden-sims README.md.</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="introduction.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M41.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l160 160c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L109.3 256 246.6 118.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-160 160z"/></svg></span>
</a>
<a rel="next prefetch" href="getting_stated/simple_ethernet_network.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M278.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-160 160c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L210.7 256 73.4 118.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l160 160z"/></svg></span>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="introduction.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M41.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l160 160c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L109.3 256 246.6 118.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-160 160z"/></svg></span>
</a>
<a rel="next prefetch" href="getting_stated/simple_ethernet_network.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M278.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-160 160c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L210.7 256 73.4 118.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l160 160z"/></svg></span>
</a>
</nav>
</div>
<template id=fa-eye><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M288 32c-80.8 0-145.5 36.8-192.6 80.6C48.6 156 17.3 208 2.5 243.7c-3.3 7.9-3.3 16.7 0 24.6C17.3 304 48.6 356 95.4 399.4C142.5 443.2 207.2 480 288 480s145.5-36.8 192.6-80.6c46.8-43.5 78.1-95.4 93-131.1c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C433.5 68.8 368.8 32 288 32zM432 256c0 79.5-64.5 144-144 144s-144-64.5-144-144s64.5-144 144-144s144 64.5 144 144zM288 192c0 35.3-28.7 64-64 64c-11.5 0-22.3-3-31.6-8.4c-.2 2.8-.4 5.5-.4 8.4c0 53 43 96 96 96s96-43 96-96s-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6z"/></svg></span></template>
<template id=fa-eye-slash><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M38.8 5.1C28.4-3.1 13.3-1.2 5.1 9.2S-1.2 34.7 9.2 42.9l592 464c10.4 8.2 25.5 6.3 33.7-4.1s6.3-25.5-4.1-33.7L525.6 386.7c39.6-40.6 66.4-86.1 79.9-118.4c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C465.5 68.8 400.8 32 320 32c-68.2 0-125 26.3-169.3 60.8L38.8 5.1zM223.1 149.5C248.6 126.2 282.7 112 320 112c79.5 0 144 64.5 144 144c0 24.9-6.3 48.3-17.4 68.7L408 294.5c5.2-11.8 8-24.8 8-38.5c0-53-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6c0 10.2-2.4 19.8-6.6 28.3l-90.3-70.8zm223.1 298L373 389.9c-16.4 6.5-34.3 10.1-53 10.1c-79.5 0-144-64.5-144-144c0-6.9 .5-13.6 1.4-20.2L83.1 161.5C60.3 191.2 44 220.8 34.5 243.7c-3.3 7.9-3.3 16.7 0 24.6c14.9 35.7 46.2 87.7 93 131.1C174.5 443.2 239.2 480 320 480c47.8 0 89.9-12.9 126.2-32.5z"/></svg></span></template>
<template id=fa-copy><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M502.6 70.63l-61.25-61.25C435.4 3.371 427.2 0 418.7 0H255.1c-35.35 0-64 28.66-64 64l.0195 256C192 355.4 220.7 384 256 384h192c35.2 0 64-28.8 64-64V93.25C512 84.77 508.6 76.63 502.6 70.63zM464 320c0 8.836-7.164 16-16 16H255.1c-8.838 0-16-7.164-16-16L239.1 64.13c0-8.836 7.164-16 16-16h128L384 96c0 17.67 14.33 32 32 32h47.1V320zM272 448c0 8.836-7.164 16-16 16H63.1c-8.838 0-16-7.164-16-16L47.98 192.1c0-8.836 7.164-16 16-16H160V128H63.99c-35.35 0-64 28.65-64 64l.0098 256C.002 483.3 28.66 512 64 512h192c35.2 0 64-28.8 64-64v-32h-47.1L272 448z"/></svg></span></template>
<template id=fa-play><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M73 39c-14.8-9.1-33.4-9.4-48.5-.9S0 62.6 0 80V432c0 17.4 9.4 33.4 24.5 41.9s33.7 8.1 48.5-.9L361 297c14.3-8.7 23-24.2 23-41s-8.7-32.2-23-41L73 39z"/></svg></span></template>
<template id=fa-clock-rotate-left><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M75 75L41 41C25.9 25.9 0 36.6 0 57.9V168c0 13.3 10.7 24 24 24H134.1c21.4 0 32.1-25.9 17-41l-30.8-30.8C155 85.5 203 64 256 64c106 0 192 86 192 192s-86 192-192 192c-40.8 0-78.6-12.7-109.7-34.4c-14.5-10.1-34.4-6.6-44.6 7.9s-6.6 34.4 7.9 44.6C151.2 495 201.7 512 256 512c141.4 0 256-114.6 256-256S397.4 0 256 0C185.3 0 121.3 28.7 75 75zm181 53c-13.3 0-24 10.7-24 24V256c0 6.4 2.5 12.5 7 17l72 72c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-65-65V152c0-13.3-10.7-24-24-24z"/></svg></span></template>
<!-- Livereload script (if served using the cli tool) -->
<script>
const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
const wsAddress = wsProtocol + "//" + location.host + "/" + "__livereload";
const socket = new WebSocket(wsAddress);
socket.onmessage = function (event) {
if (event.data === "reload") {
socket.close();
location.reload();
}
};
window.onbeforeunload = function() {
socket.close();
}
</script>
<script>
window.playground_copyable = true;
</script>
<script src="elasticlunr-ef4e11c1.min.js"></script>
<script src="mark-09e88c2c.min.js"></script>
<script src="searcher-c2a407aa.js"></script>
<script src="clipboard-1626706a.min.js"></script>
<script src="highlight-abc7f01d.js"></script>
<script src="book-a0b12cfe.js"></script>
<!-- Custom JS scripts -->
</div>
</body>
</html>

1599
userGuide/book/print.html Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,555 @@
'use strict';
/* global Mark, elasticlunr, path_to_root */
window.search = window.search || {};
(function search() {
// Search functionality
//
// You can use !hasFocus() to prevent keyhandling in your key
// event handlers while the user is typing their search.
if (!Mark || !elasticlunr) {
return;
}
// eslint-disable-next-line max-len
// IE 11 Compatibility from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith
if (!String.prototype.startsWith) {
String.prototype.startsWith = function(search, pos) {
return this.substr(!pos || pos < 0 ? 0 : +pos, search.length) === search;
};
}
const search_wrap = document.getElementById('mdbook-search-wrapper'),
searchbar_outer = document.getElementById('mdbook-searchbar-outer'),
searchbar = document.getElementById('mdbook-searchbar'),
searchresults = document.getElementById('mdbook-searchresults'),
searchresults_outer = document.getElementById('mdbook-searchresults-outer'),
searchresults_header = document.getElementById('mdbook-searchresults-header'),
searchicon = document.getElementById('mdbook-search-toggle'),
content = document.getElementById('mdbook-content'),
// SVG text elements don't render if inside a <mark> tag.
mark_exclude = ['text'],
marker = new Mark(content),
URL_SEARCH_PARAM = 'search',
URL_MARK_PARAM = 'highlight';
let current_searchterm = '',
doc_urls = [],
search_options = {
bool: 'AND',
expand: true,
fields: {
title: {boost: 1},
body: {boost: 1},
breadcrumbs: {boost: 0},
},
},
searchindex = null,
results_options = {
teaser_word_count: 30,
limit_results: 30,
},
teaser_count = 0;
function hasFocus() {
return searchbar === document.activeElement;
}
function removeChildren(elem) {
while (elem.firstChild) {
elem.removeChild(elem.firstChild);
}
}
// Helper to parse a url into its building blocks.
function parseURL(url) {
const a = document.createElement('a');
a.href = url;
return {
source: url,
protocol: a.protocol.replace(':', ''),
host: a.hostname,
port: a.port,
params: (function() {
const ret = {};
const seg = a.search.replace(/^\?/, '').split('&');
for (const part of seg) {
if (!part) {
continue;
}
const s = part.split('=');
ret[s[0]] = s[1];
}
return ret;
})(),
file: (a.pathname.match(/\/([^/?#]+)$/i) || ['', ''])[1],
hash: a.hash.replace('#', ''),
path: a.pathname.replace(/^([^/])/, '/$1'),
};
}
// Helper to recreate a url string from its building blocks.
function renderURL(urlobject) {
let url = urlobject.protocol + '://' + urlobject.host;
if (urlobject.port !== '') {
url += ':' + urlobject.port;
}
url += urlobject.path;
let joiner = '?';
for (const prop in urlobject.params) {
if (Object.prototype.hasOwnProperty.call(urlobject.params, prop)) {
url += joiner + prop + '=' + urlobject.params[prop];
joiner = '&';
}
}
if (urlobject.hash !== '') {
url += '#' + urlobject.hash;
}
return url;
}
// Helper to escape html special chars for displaying the teasers
const escapeHTML = (function() {
const MAP = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&#34;',
'\'': '&#39;',
};
const repl = function(c) {
return MAP[c];
};
return function(s) {
return s.replace(/[&<>'"]/g, repl);
};
})();
function formatSearchMetric(count, searchterm) {
if (count === 1) {
return count + ' search result for \'' + searchterm + '\':';
} else if (count === 0) {
return 'No search results for \'' + searchterm + '\'.';
} else {
return count + ' search results for \'' + searchterm + '\':';
}
}
function formatSearchResult(result, searchterms) {
const teaser = makeTeaser(escapeHTML(result.doc.body), searchterms);
teaser_count++;
// The ?URL_MARK_PARAM= parameter belongs inbetween the page and the #heading-anchor
const url = doc_urls[result.ref].split('#');
if (url.length === 1) { // no anchor found
url.push('');
}
// encodeURIComponent escapes all chars that could allow an XSS except
// for '. Due to that we also manually replace ' with its url-encoded
// representation (%27).
const encoded_search = encodeURIComponent(searchterms.join(' ')).replace(/'/g, '%27');
return '<a href="' + path_to_root + url[0] + '?' + URL_MARK_PARAM + '=' + encoded_search
+ '#' + url[1] + '" aria-details="mdbook-teaser_' + teaser_count + '">'
+ result.doc.breadcrumbs + '</a>'
+ '<span class="teaser" id="mdbook-teaser_' + teaser_count
+ '" aria-label="Search Result Teaser">' + teaser + '</span>';
}
function makeTeaser(body, searchterms) {
// The strategy is as follows:
// First, assign a value to each word in the document:
// Words that correspond to search terms (stemmer aware): 40
// Normal words: 2
// First word in a sentence: 8
// Then use a sliding window with a constant number of words and count the
// sum of the values of the words within the window. Then use the window that got the
// maximum sum. If there are multiple maximas, then get the last one.
// Enclose the terms in <em>.
const stemmed_searchterms = searchterms.map(function(w) {
return elasticlunr.stemmer(w.toLowerCase());
});
const searchterm_weight = 40;
const weighted = []; // contains elements of ["word", weight, index_in_document]
// split in sentences, then words
const sentences = body.toLowerCase().split('. ');
let index = 0;
let value = 0;
let searchterm_found = false;
for (const sentenceindex in sentences) {
const words = sentences[sentenceindex].split(' ');
value = 8;
for (const wordindex in words) {
const word = words[wordindex];
if (word.length > 0) {
for (const searchtermindex in stemmed_searchterms) {
if (elasticlunr.stemmer(word).startsWith(
stemmed_searchterms[searchtermindex])
) {
value = searchterm_weight;
searchterm_found = true;
}
}
weighted.push([word, value, index]);
value = 2;
}
index += word.length;
index += 1; // ' ' or '.' if last word in sentence
}
index += 1; // because we split at a two-char boundary '. '
}
if (weighted.length === 0) {
return body;
}
const window_weight = [];
const window_size = Math.min(weighted.length, results_options.teaser_word_count);
let cur_sum = 0;
for (let wordindex = 0; wordindex < window_size; wordindex++) {
cur_sum += weighted[wordindex][1];
}
window_weight.push(cur_sum);
for (let wordindex = 0; wordindex < weighted.length - window_size; wordindex++) {
cur_sum -= weighted[wordindex][1];
cur_sum += weighted[wordindex + window_size][1];
window_weight.push(cur_sum);
}
let max_sum_window_index = 0;
if (searchterm_found) {
let max_sum = 0;
// backwards
for (let i = window_weight.length - 1; i >= 0; i--) {
if (window_weight[i] > max_sum) {
max_sum = window_weight[i];
max_sum_window_index = i;
}
}
} else {
max_sum_window_index = 0;
}
// add <em/> around searchterms
const teaser_split = [];
index = weighted[max_sum_window_index][2];
for (let i = max_sum_window_index; i < max_sum_window_index + window_size; i++) {
const word = weighted[i];
if (index < word[2]) {
// missing text from index to start of `word`
teaser_split.push(body.substring(index, word[2]));
index = word[2];
}
if (word[1] === searchterm_weight) {
teaser_split.push('<em>');
}
index = word[2] + word[0].length;
teaser_split.push(body.substring(word[2], index));
if (word[1] === searchterm_weight) {
teaser_split.push('</em>');
}
}
return teaser_split.join('');
}
function init(config) {
results_options = config.results_options;
search_options = config.search_options;
doc_urls = config.doc_urls;
searchindex = elasticlunr.Index.load(config.index);
searchbar_outer.classList.remove('searching');
searchbar.focus();
const searchterm = searchbar.value.trim();
if (searchterm !== '') {
searchbar.classList.add('active');
doSearch(searchterm);
}
}
function initSearchInteractions(config) {
// Set up events
searchicon.addEventListener('click', () => {
searchIconClickHandler();
}, false);
searchbar.addEventListener('keyup', () => {
searchbarKeyUpHandler();
}, false);
document.addEventListener('keydown', e => {
globalKeyHandler(e);
}, false);
// If the user uses the browser buttons, do the same as if a reload happened
window.onpopstate = () => {
doSearchOrMarkFromUrl();
};
// Suppress "submit" events so the page doesn't reload when the user presses Enter
document.addEventListener('submit', e => {
e.preventDefault();
}, false);
// If reloaded, do the search or mark again, depending on the current url parameters
doSearchOrMarkFromUrl();
// Exported functions
config.hasFocus = hasFocus;
}
initSearchInteractions(window.search);
function unfocusSearchbar() {
// hacky, but just focusing a div only works once
const tmp = document.createElement('input');
tmp.setAttribute('style', 'position: absolute; opacity: 0;');
searchicon.appendChild(tmp);
tmp.focus();
tmp.remove();
}
// On reload or browser history backwards/forwards events, parse the url and do search or mark
function doSearchOrMarkFromUrl() {
// Check current URL for search request
const url = parseURL(window.location.href);
if (Object.prototype.hasOwnProperty.call(url.params, URL_SEARCH_PARAM)
&& url.params[URL_SEARCH_PARAM] !== '') {
showSearch(true);
searchbar.value = decodeURIComponent(
(url.params[URL_SEARCH_PARAM] + '').replace(/\+/g, '%20'));
searchbarKeyUpHandler(); // -> doSearch()
} else {
showSearch(false);
}
if (Object.prototype.hasOwnProperty.call(url.params, URL_MARK_PARAM)) {
const words = decodeURIComponent(url.params[URL_MARK_PARAM]).split(' ');
marker.mark(words, {
exclude: mark_exclude,
});
const markers = document.querySelectorAll('mark');
const hide = () => {
for (let i = 0; i < markers.length; i++) {
markers[i].classList.add('fade-out');
window.setTimeout(() => {
marker.unmark();
}, 300);
}
};
for (let i = 0; i < markers.length; i++) {
markers[i].addEventListener('click', hide);
}
}
}
// Eventhandler for keyevents on `document`
function globalKeyHandler(e) {
if (e.altKey ||
e.ctrlKey ||
e.metaKey ||
e.shiftKey ||
e.target.type === 'textarea' ||
e.target.type === 'text' ||
!hasFocus() && /^(?:input|select|textarea)$/i.test(e.target.nodeName)
) {
return;
}
if (e.key === 'Escape') {
e.preventDefault();
searchbar.classList.remove('active');
setSearchUrlParameters('',
searchbar.value.trim() !== '' ? 'push' : 'replace');
if (hasFocus()) {
unfocusSearchbar();
}
showSearch(false);
marker.unmark();
} else if (!hasFocus() && (e.key === 's' || e.key === '/')) {
e.preventDefault();
showSearch(true);
window.scrollTo(0, 0);
searchbar.select();
} else if (hasFocus() && (e.key === 'ArrowDown'
|| e.key === 'Enter')) {
e.preventDefault();
const first = searchresults.firstElementChild;
if (first !== null) {
unfocusSearchbar();
first.classList.add('focus');
if (e.key === 'Enter') {
window.location.assign(first.querySelector('a'));
}
}
} else if (!hasFocus() && (e.key === 'ArrowDown'
|| e.key === 'ArrowUp'
|| e.key === 'Enter')) {
// not `:focus` because browser does annoying scrolling
const focused = searchresults.querySelector('li.focus');
if (!focused) {
return;
}
e.preventDefault();
if (e.key === 'ArrowDown') {
const next = focused.nextElementSibling;
if (next) {
focused.classList.remove('focus');
next.classList.add('focus');
}
} else if (e.key === 'ArrowUp') {
focused.classList.remove('focus');
const prev = focused.previousElementSibling;
if (prev) {
prev.classList.add('focus');
} else {
searchbar.select();
}
} else { // Enter
window.location.assign(focused.querySelector('a'));
}
}
}
function loadSearchScript(url, id) {
if (document.getElementById(id)) {
return;
}
searchbar_outer.classList.add('searching');
const script = document.createElement('script');
script.src = url;
script.id = id;
script.onload = () => init(window.search);
script.onerror = error => {
console.error(`Failed to load \`${url}\`: ${error}`);
};
document.head.append(script);
}
function showSearch(yes) {
if (yes) {
loadSearchScript(
window.path_to_searchindex_js ||
path_to_root + 'searchindex-43c2d326.js',
'mdbook-search-index');
search_wrap.classList.remove('hidden');
searchicon.setAttribute('aria-expanded', 'true');
} else {
search_wrap.classList.add('hidden');
searchicon.setAttribute('aria-expanded', 'false');
const results = searchresults.children;
for (let i = 0; i < results.length; i++) {
results[i].classList.remove('focus');
}
}
}
function showResults(yes) {
if (yes) {
searchresults_outer.classList.remove('hidden');
} else {
searchresults_outer.classList.add('hidden');
}
}
// Eventhandler for search icon
function searchIconClickHandler() {
if (search_wrap.classList.contains('hidden')) {
showSearch(true);
window.scrollTo(0, 0);
searchbar.select();
} else {
showSearch(false);
}
}
// Eventhandler for keyevents while the searchbar is focused
function searchbarKeyUpHandler() {
const searchterm = searchbar.value.trim();
if (searchterm !== '') {
searchbar.classList.add('active');
doSearch(searchterm);
} else {
searchbar.classList.remove('active');
showResults(false);
removeChildren(searchresults);
}
setSearchUrlParameters(searchterm, 'push_if_new_search_else_replace');
// Remove marks
marker.unmark();
}
// Update current url with ?URL_SEARCH_PARAM= parameter, remove ?URL_MARK_PARAM and
// `#heading-anchor`. `action` can be one of "push", "replace",
// "push_if_new_search_else_replace" and replaces or pushes a new browser history item.
// "push_if_new_search_else_replace" pushes if there is no `?URL_SEARCH_PARAM=abc` yet.
function setSearchUrlParameters(searchterm, action) {
const url = parseURL(window.location.href);
const first_search = !Object.prototype.hasOwnProperty.call(url.params, URL_SEARCH_PARAM);
if (searchterm !== '' || action === 'push_if_new_search_else_replace') {
url.params[URL_SEARCH_PARAM] = searchterm;
delete url.params[URL_MARK_PARAM];
url.hash = '';
} else {
delete url.params[URL_MARK_PARAM];
delete url.params[URL_SEARCH_PARAM];
}
// A new search will also add a new history item, so the user can go back
// to the page prior to searching. A updated search term will only replace
// the url.
if (action === 'push' || action === 'push_if_new_search_else_replace' && first_search ) {
history.pushState({}, document.title, renderURL(url));
} else if (action === 'replace' ||
action === 'push_if_new_search_else_replace' &&
!first_search
) {
history.replaceState({}, document.title, renderURL(url));
}
}
function doSearch(searchterm) {
// Don't search the same twice
if (current_searchterm === searchterm) {
return;
}
searchbar_outer.classList.add('searching');
if (searchindex === null) {
return;
}
current_searchterm = searchterm;
// Do the actual search
const results = searchindex.search(searchterm, search_options);
const resultcount = Math.min(results.length, results_options.limit_results);
// Display search metrics
searchresults_header.innerText = formatSearchMetric(resultcount, searchterm);
// Clear and insert results
const searchterms = searchterm.split(' ');
removeChildren(searchresults);
for (let i = 0; i < resultcount ; i++) {
const resultElem = document.createElement('li');
resultElem.innerHTML = formatSearchResult(results[i], searchterms);
searchresults.appendChild(resultElem);
}
// Display results
showResults(true);
searchbar_outer.classList.remove('searching');
}
// Exported functions
search.hasFocus = hasFocus;
})(window.search);

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,454 @@
// Populate the sidebar
//
// This is a script, and not included directly in the page, to control the total size of the book.
// The TOC contains an entry for each page, so if each page includes a copy of the TOC,
// the total size of the page becomes O(n**2).
class MDBookSidebarScrollbox extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
this.innerHTML = '<ol class="chapter"><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="introduction.html">Introduction</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="prerequisites.html">Prerequisites</a></span></li><li class="chapter-item expanded "><li class="part-title">Getting started</li></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="getting_stated/simple_ethernet_network.html"><strong aria-hidden="true">1.</strong> Creation of a simple ethernet network</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="getting_stated/network_customization.html"><strong aria-hidden="true">2.</strong> Network customization</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="getting_stated/simple_tsn_network.html"><strong aria-hidden="true">3.</strong> Creation of a simple tsn network</a></span></li><li class="chapter-item expanded "><li class="part-title">Advanced uses</li></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><span><strong aria-hidden="true">4.</strong> Work In Progress</span></span></li></ol>';
// Set the current, active page, and reveal it if it's hidden
let current_page = document.location.href.toString().split('#')[0].split('?')[0];
if (current_page.endsWith('/')) {
current_page += 'index.html';
}
const links = Array.prototype.slice.call(this.querySelectorAll('a'));
const l = links.length;
for (let i = 0; i < l; ++i) {
const link = links[i];
const href = link.getAttribute('href');
if (href && !href.startsWith('#') && !/^(?:[a-z+]+:)?\/\//.test(href)) {
link.href = path_to_root + href;
}
// The 'index' page is supposed to alias the first chapter in the book.
if (link.href === current_page
|| i === 0
&& path_to_root === ''
&& current_page.endsWith('/index.html')) {
link.classList.add('active');
let parent = link.parentElement;
while (parent) {
if (parent.tagName === 'LI' && parent.classList.contains('chapter-item')) {
parent.classList.add('expanded');
}
parent = parent.parentElement;
}
}
}
// Track and set sidebar scroll position
this.addEventListener('click', e => {
if (e.target.tagName === 'A') {
const clientRect = e.target.getBoundingClientRect();
const sidebarRect = this.getBoundingClientRect();
sessionStorage.setItem('sidebar-scroll-offset', clientRect.top - sidebarRect.top);
}
}, { passive: true });
const sidebarScrollOffset = sessionStorage.getItem('sidebar-scroll-offset');
sessionStorage.removeItem('sidebar-scroll-offset');
if (sidebarScrollOffset !== null) {
// preserve sidebar scroll position when navigating via links within sidebar
const activeSection = this.querySelector('.active');
if (activeSection) {
const clientRect = activeSection.getBoundingClientRect();
const sidebarRect = this.getBoundingClientRect();
const currentOffset = clientRect.top - sidebarRect.top;
this.scrollTop += currentOffset - parseFloat(sidebarScrollOffset);
}
} else {
// scroll sidebar to current active section when navigating via
// 'next/previous chapter' buttons
const activeSection = document.querySelector('#mdbook-sidebar .active');
if (activeSection) {
activeSection.scrollIntoView({ block: 'center' });
}
}
// Toggle buttons
const sidebarAnchorToggles = document.querySelectorAll('.chapter-fold-toggle');
function toggleSection(ev) {
ev.currentTarget.parentElement.parentElement.classList.toggle('expanded');
}
Array.from(sidebarAnchorToggles).forEach(el => {
el.addEventListener('click', toggleSection);
});
}
}
window.customElements.define('mdbook-sidebar-scrollbox', MDBookSidebarScrollbox);
// ---------------------------------------------------------------------------
// Support for dynamically adding headers to the sidebar.
(function() {
// This is used to detect which direction the page has scrolled since the
// last scroll event.
let lastKnownScrollPosition = 0;
// This is the threshold in px from the top of the screen where it will
// consider a header the "current" header when scrolling down.
const defaultDownThreshold = 150;
// Same as defaultDownThreshold, except when scrolling up.
const defaultUpThreshold = 300;
// The threshold is a virtual horizontal line on the screen where it
// considers the "current" header to be above the line. The threshold is
// modified dynamically to handle headers that are near the bottom of the
// screen, and to slightly offset the behavior when scrolling up vs down.
let threshold = defaultDownThreshold;
// This is used to disable updates while scrolling. This is needed when
// clicking the header in the sidebar, which triggers a scroll event. It
// is somewhat finicky to detect when the scroll has finished, so this
// uses a relatively dumb system of disabling scroll updates for a short
// time after the click.
let disableScroll = false;
// Array of header elements on the page.
let headers;
// Array of li elements that are initially collapsed headers in the sidebar.
// I'm not sure why eslint seems to have a false positive here.
// eslint-disable-next-line prefer-const
let headerToggles = [];
// This is a debugging tool for the threshold which you can enable in the console.
let thresholdDebug = false;
// Updates the threshold based on the scroll position.
function updateThreshold() {
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
const windowHeight = window.innerHeight;
const documentHeight = document.documentElement.scrollHeight;
// The number of pixels below the viewport, at most documentHeight.
// This is used to push the threshold down to the bottom of the page
// as the user scrolls towards the bottom.
const pixelsBelow = Math.max(0, documentHeight - (scrollTop + windowHeight));
// The number of pixels above the viewport, at least defaultDownThreshold.
// Similar to pixelsBelow, this is used to push the threshold back towards
// the top when reaching the top of the page.
const pixelsAbove = Math.max(0, defaultDownThreshold - scrollTop);
// How much the threshold should be offset once it gets close to the
// bottom of the page.
const bottomAdd = Math.max(0, windowHeight - pixelsBelow - defaultDownThreshold);
let adjustedBottomAdd = bottomAdd;
// Adjusts bottomAdd for a small document. The calculation above
// assumes the document is at least twice the windowheight in size. If
// it is less than that, then bottomAdd needs to be shrunk
// proportional to the difference in size.
if (documentHeight < windowHeight * 2) {
const maxPixelsBelow = documentHeight - windowHeight;
const t = 1 - pixelsBelow / Math.max(1, maxPixelsBelow);
const clamp = Math.max(0, Math.min(1, t));
adjustedBottomAdd *= clamp;
}
let scrollingDown = true;
if (scrollTop < lastKnownScrollPosition) {
scrollingDown = false;
}
if (scrollingDown) {
// When scrolling down, move the threshold up towards the default
// downwards threshold position. If near the bottom of the page,
// adjustedBottomAdd will offset the threshold towards the bottom
// of the page.
const amountScrolledDown = scrollTop - lastKnownScrollPosition;
const adjustedDefault = defaultDownThreshold + adjustedBottomAdd;
threshold = Math.max(adjustedDefault, threshold - amountScrolledDown);
} else {
// When scrolling up, move the threshold down towards the default
// upwards threshold position. If near the bottom of the page,
// quickly transition the threshold back up where it normally
// belongs.
const amountScrolledUp = lastKnownScrollPosition - scrollTop;
const adjustedDefault = defaultUpThreshold - pixelsAbove
+ Math.max(0, adjustedBottomAdd - defaultDownThreshold);
threshold = Math.min(adjustedDefault, threshold + amountScrolledUp);
}
if (documentHeight <= windowHeight) {
threshold = 0;
}
if (thresholdDebug) {
const id = 'mdbook-threshold-debug-data';
let data = document.getElementById(id);
if (data === null) {
data = document.createElement('div');
data.id = id;
data.style.cssText = `
position: fixed;
top: 50px;
right: 10px;
background-color: 0xeeeeee;
z-index: 9999;
pointer-events: none;
`;
document.body.appendChild(data);
}
data.innerHTML = `
<table>
<tr><td>documentHeight</td><td>${documentHeight.toFixed(1)}</td></tr>
<tr><td>windowHeight</td><td>${windowHeight.toFixed(1)}</td></tr>
<tr><td>scrollTop</td><td>${scrollTop.toFixed(1)}</td></tr>
<tr><td>pixelsAbove</td><td>${pixelsAbove.toFixed(1)}</td></tr>
<tr><td>pixelsBelow</td><td>${pixelsBelow.toFixed(1)}</td></tr>
<tr><td>bottomAdd</td><td>${bottomAdd.toFixed(1)}</td></tr>
<tr><td>adjustedBottomAdd</td><td>${adjustedBottomAdd.toFixed(1)}</td></tr>
<tr><td>scrollingDown</td><td>${scrollingDown}</td></tr>
<tr><td>threshold</td><td>${threshold.toFixed(1)}</td></tr>
</table>
`;
drawDebugLine();
}
lastKnownScrollPosition = scrollTop;
}
function drawDebugLine() {
if (!document.body) {
return;
}
const id = 'mdbook-threshold-debug-line';
const existingLine = document.getElementById(id);
if (existingLine) {
existingLine.remove();
}
const line = document.createElement('div');
line.id = id;
line.style.cssText = `
position: fixed;
top: ${threshold}px;
left: 0;
width: 100vw;
height: 2px;
background-color: red;
z-index: 9999;
pointer-events: none;
`;
document.body.appendChild(line);
}
function mdbookEnableThresholdDebug() {
thresholdDebug = true;
updateThreshold();
drawDebugLine();
}
window.mdbookEnableThresholdDebug = mdbookEnableThresholdDebug;
// Updates which headers in the sidebar should be expanded. If the current
// header is inside a collapsed group, then it, and all its parents should
// be expanded.
function updateHeaderExpanded(currentA) {
// Add expanded to all header-item li ancestors.
let current = currentA.parentElement;
while (current) {
if (current.tagName === 'LI' && current.classList.contains('header-item')) {
current.classList.add('expanded');
}
current = current.parentElement;
}
}
// Updates which header is marked as the "current" header in the sidebar.
// This is done with a virtual Y threshold, where headers at or below
// that line will be considered the current one.
function updateCurrentHeader() {
if (!headers || !headers.length) {
return;
}
// Reset the classes, which will be rebuilt below.
const els = document.getElementsByClassName('current-header');
for (const el of els) {
el.classList.remove('current-header');
}
for (const toggle of headerToggles) {
toggle.classList.remove('expanded');
}
// Find the last header that is above the threshold.
let lastHeader = null;
for (const header of headers) {
const rect = header.getBoundingClientRect();
if (rect.top <= threshold) {
lastHeader = header;
} else {
break;
}
}
if (lastHeader === null) {
lastHeader = headers[0];
const rect = lastHeader.getBoundingClientRect();
const windowHeight = window.innerHeight;
if (rect.top >= windowHeight) {
return;
}
}
// Get the anchor in the summary.
const href = '#' + lastHeader.id;
const a = [...document.querySelectorAll('.header-in-summary')]
.find(element => element.getAttribute('href') === href);
if (!a) {
return;
}
a.classList.add('current-header');
updateHeaderExpanded(a);
}
// Updates which header is "current" based on the threshold line.
function reloadCurrentHeader() {
if (disableScroll) {
return;
}
updateThreshold();
updateCurrentHeader();
}
// When clicking on a header in the sidebar, this adjusts the threshold so
// that it is located next to the header. This is so that header becomes
// "current".
function headerThresholdClick(event) {
// See disableScroll description why this is done.
disableScroll = true;
setTimeout(() => {
disableScroll = false;
}, 100);
// requestAnimationFrame is used to delay the update of the "current"
// header until after the scroll is done, and the header is in the new
// position.
requestAnimationFrame(() => {
requestAnimationFrame(() => {
// Closest is needed because if it has child elements like <code>.
const a = event.target.closest('a');
const href = a.getAttribute('href');
const targetId = href.substring(1);
const targetElement = document.getElementById(targetId);
if (targetElement) {
threshold = targetElement.getBoundingClientRect().bottom;
updateCurrentHeader();
}
});
});
}
// Takes the nodes from the given head and copies them over to the
// destination, along with some filtering.
function filterHeader(source, dest) {
const clone = source.cloneNode(true);
clone.querySelectorAll('mark').forEach(mark => {
mark.replaceWith(...mark.childNodes);
});
dest.append(...clone.childNodes);
}
// Scans page for headers and adds them to the sidebar.
document.addEventListener('DOMContentLoaded', function() {
const activeSection = document.querySelector('#mdbook-sidebar .active');
if (activeSection === null) {
return;
}
const main = document.getElementsByTagName('main')[0];
headers = Array.from(main.querySelectorAll('h2, h3, h4, h5, h6'))
.filter(h => h.id !== '' && h.children.length && h.children[0].tagName === 'A');
if (headers.length === 0) {
return;
}
// Build a tree of headers in the sidebar.
const stack = [];
const firstLevel = parseInt(headers[0].tagName.charAt(1));
for (let i = 1; i < firstLevel; i++) {
const ol = document.createElement('ol');
ol.classList.add('section');
if (stack.length > 0) {
stack[stack.length - 1].ol.appendChild(ol);
}
stack.push({level: i + 1, ol: ol});
}
// The level where it will start folding deeply nested headers.
const foldLevel = 3;
for (let i = 0; i < headers.length; i++) {
const header = headers[i];
const level = parseInt(header.tagName.charAt(1));
const currentLevel = stack[stack.length - 1].level;
if (level > currentLevel) {
// Begin nesting to this level.
for (let nextLevel = currentLevel + 1; nextLevel <= level; nextLevel++) {
const ol = document.createElement('ol');
ol.classList.add('section');
const last = stack[stack.length - 1];
const lastChild = last.ol.lastChild;
// Handle the case where jumping more than one nesting
// level, which doesn't have a list item to place this new
// list inside of.
if (lastChild) {
lastChild.appendChild(ol);
} else {
last.ol.appendChild(ol);
}
stack.push({level: nextLevel, ol: ol});
}
} else if (level < currentLevel) {
while (stack.length > 1 && stack[stack.length - 1].level > level) {
stack.pop();
}
}
const li = document.createElement('li');
li.classList.add('header-item');
li.classList.add('expanded');
if (level < foldLevel) {
li.classList.add('expanded');
}
const span = document.createElement('span');
span.classList.add('chapter-link-wrapper');
const a = document.createElement('a');
span.appendChild(a);
a.href = '#' + header.id;
a.classList.add('header-in-summary');
filterHeader(header.children[0], a);
a.addEventListener('click', headerThresholdClick);
const nextHeader = headers[i + 1];
if (nextHeader !== undefined) {
const nextLevel = parseInt(nextHeader.tagName.charAt(1));
if (nextLevel > level && level >= foldLevel) {
const toggle = document.createElement('a');
toggle.classList.add('chapter-fold-toggle');
toggle.classList.add('header-toggle');
toggle.addEventListener('click', () => {
li.classList.toggle('expanded');
});
const toggleDiv = document.createElement('div');
toggleDiv.textContent = '❱';
toggle.appendChild(toggleDiv);
span.appendChild(toggle);
headerToggles.push(li);
}
}
li.appendChild(span);
const currentParent = stack[stack.length - 1];
currentParent.ol.appendChild(li);
}
const onThisPage = document.createElement('div');
onThisPage.classList.add('on-this-page');
onThisPage.append(stack[0].ol);
const activeItemSpan = activeSection.parentElement;
activeItemSpan.after(onThisPage);
});
document.addEventListener('DOMContentLoaded', reloadCurrentHeader);
document.addEventListener('scroll', reloadCurrentHeader, { passive: true });
})();

31
userGuide/book/toc.html Normal file
View File

@@ -0,0 +1,31 @@
<!DOCTYPE HTML>
<html lang="en" class="light" dir="ltr">
<head>
<!-- sidebar iframe generated using mdBook
This is a frame, and not included directly in the page, to control the total size of the
book. The TOC contains an entry for each page, so if each page includes a copy of the TOC,
the total size of the page becomes O(n**2).
The frame is only used as a fallback when JS is turned off. When it's on, the sidebar is
instead added to the main page by `toc.js` instead. The JavaScript mode is better
because, when running in a `file:///` URL, the iframed page would not be Same-Origin as
the rest of the page, so the sidebar and the main page theme would fall out of sync.
-->
<meta charset="UTF-8">
<meta name="robots" content="noindex">
<!-- Custom HTML head -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="stylesheet" href="css/variables-8adf115d.css">
<link rel="stylesheet" href="css/general-2459343d.css">
<link rel="stylesheet" href="css/chrome-ae938929.css">
<link rel="stylesheet" href="css/print-9e4910d8.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="fonts/fonts-9644e21d.css">
<!-- Custom theme stylesheets -->
</head>
<body class="sidebar-iframe-inner">
<ol class="chapter"><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="introduction.html" target="_parent">Introduction</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="prerequisites.html" target="_parent">Prerequisites</a></span></li><li class="chapter-item expanded "><li class="part-title">Getting started</li></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="getting_stated/simple_ethernet_network.html" target="_parent"><strong aria-hidden="true">1.</strong> Creation of a simple ethernet network</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="getting_stated/network_customization.html" target="_parent"><strong aria-hidden="true">2.</strong> Network customization</a></span></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><a href="getting_stated/simple_tsn_network.html" target="_parent"><strong aria-hidden="true">3.</strong> Creation of a simple tsn network</a></span></li><li class="chapter-item expanded "><li class="part-title">Advanced uses</li></li><li class="chapter-item expanded "><span class="chapter-link-wrapper"><span><strong aria-hidden="true">4.</strong> Work In Progress</span></span></li></ol>
</body>
</html>

View File

@@ -0,0 +1,104 @@
/* Tomorrow Night Theme */
/* https://github.com/jmblog/color-themes-for-highlightjs */
/* Original theme - https://github.com/chriskempson/tomorrow-theme */
/* https://github.com/jmblog/color-themes-for-highlightjs */
/* Tomorrow Comment */
.hljs-comment {
color: #969896;
}
/* Tomorrow Red */
.hljs-variable,
.hljs-attribute,
.hljs-attr,
.hljs-tag,
.hljs-regexp,
.ruby .hljs-constant,
.xml .hljs-tag .hljs-title,
.xml .hljs-pi,
.xml .hljs-doctype,
.html .hljs-doctype,
.css .hljs-id,
.css .hljs-class,
.css .hljs-pseudo {
color: #cc6666;
}
/* Tomorrow Orange */
.hljs-number,
.hljs-preprocessor,
.hljs-pragma,
.hljs-built_in,
.hljs-literal,
.hljs-params,
.hljs-constant {
color: #de935f;
}
/* Tomorrow Yellow */
.ruby .hljs-class .hljs-title,
.css .hljs-rule .hljs-attribute {
color: #f0c674;
}
/* Tomorrow Green */
.hljs-string,
.hljs-value,
.hljs-inheritance,
.hljs-header,
.hljs-name,
.ruby .hljs-symbol,
.xml .hljs-cdata {
color: #b5bd68;
}
/* Tomorrow Aqua */
.hljs-title,
.hljs-section,
.css .hljs-hexcolor {
color: #8abeb7;
}
/* Tomorrow Blue */
.hljs-function,
.python .hljs-decorator,
.python .hljs-title,
.ruby .hljs-function .hljs-title,
.ruby .hljs-title .hljs-keyword,
.perl .hljs-sub,
.javascript .hljs-title,
.coffeescript .hljs-title {
color: #81a2be;
}
/* Tomorrow Purple */
.hljs-keyword,
.javascript .hljs-function {
color: #b294bb;
}
.hljs {
display: block;
overflow-x: auto;
background: #1d1f21;
color: #c5c8c6;
}
.coffeescript .javascript,
.javascript .xml,
.tex .hljs-formula,
.xml .javascript,
.xml .vbscript,
.xml .css,
.xml .hljs-cdata {
opacity: 0.5;
}
.hljs-addition {
color: #718c00;
}
.hljs-deletion {
color: #c82829;
}

10
userGuide/src/SUMMARY.md Normal file
View File

@@ -0,0 +1,10 @@
[Introduction](./introduction.md)
[Prerequisites](./prerequisites.md)
# Getting started
- [Creation of a simple ethernet network](./getting_stated/simple_ethernet_network.md)
- [Network customization](./getting_stated/network_customization.md)
- [Creation of a simple tsn network](./getting_stated/simple_tsn_network.md)
# Advanced uses
- [Work In Progress]()

View File

@@ -0,0 +1 @@
# WIP

View File

@@ -0,0 +1,298 @@
# Network customization
## Introduction
In the previous chapter, we wrote a simulation script for a simple Ethernet network. In this chapter, we will discuss how to customize it using the attributes of the different classes used.
## Attributes in ns-3
To organize access and configuration of instantiated object parameters, ns-3 uses its own attribute system.
In the previous chapter, we already implemented this overlay using the “SetAttribute()” function to configure the application. This function has two arguments. The first is a string corresponding to the name of the attribute to be changed. The second is the value to be assigned to this attribute.
The various attributes available for each object are visible in the C++ implementation of each object. Here is an example of the EthernetChannel object described in contrib/ethernet/model/ethernet-channel.cc.
```c++
TypeId
EthernetChannel::GetTypeId()
{
static TypeId tid =
TypeId("ns3::EthernetChannel")
.SetParent<Channel>()
.SetGroupName("Ethernet")
.AddConstructor<EthernetChannel>()
.AddAttribute("Delay",
"Propagation delay through the channel",
TimeValue(NanoSeconds(25)),
MakeTimeAccessor(&EthernetChannel::m_delay),
MakeTimeChecker())
.AddTraceSource("TxRxEthernet",
"Trace source indicating transmission of packet "
"from the EthernetChannel, used by the Animation "
"interface.",
MakeTraceSourceAccessor(&EthernetChannel::m_txrxEthernet),
"ns3::EthernetChannel::TxRxAnimationCallback");
return tid;
}
```
We can see that this object has only one attribute called Delay, which allows you to configure the propagation delay. It is of type Time and has a default value of 25ns.
Thus, it is possible to configure the propagation delay in the previous simulation script as follows:
```c++
[...]
//Create Ethernet Channels and connect switch to the end-stations
Ptr<EthernetChannel> channel0 = CreateObject<EthernetChannel>();
channel0->SetAttribute("Delay", TimeValue(NanoSeconds(50)));
net0->Attach(channel0);
swnet0->Attach(channel0);
Ptr<EthernetChannel> channel1 = CreateObject<EthernetChannel>();
channel1->SetAttribute("Delay", TimeValue(NanoSeconds(75)));
net1->Attach(channel1);
swnet1->Attach(channel1);
Ptr<EthernetChannel> channel2 = CreateObject<EthernetChannel>();
channel2->SetAttribute("Delay", TimeValue(NanoSeconds(100)));
net2->Attach(channel2);
swnet2->Attach(channel2);
[...]
```
## Common attributes
Here are examples of the attributes most often used in Ethernet network simulations.
```c++
[...]
//Create and add a netDevice to each end-station node
Ptr<EthernetNetDevice> net0 = CreateObject<EthernetNetDevice>();
net0->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n0->AddDevice(net0);
Names::Add("ES1#01", net0);
Ptr<EthernetNetDevice> net1 = CreateObject<EthernetNetDevice>();
net1->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n1->AddDevice(net1);
Names::Add("ES2#01", net1);
Ptr<EthernetNetDevice> net2 = CreateObject<EthernetNetDevice>();
net2->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n2->AddDevice(net2);
Names::Add("ES3#01", net2);
//Create and add a netDevice to each switch port
Ptr<EthernetNetDevice> swnet0 = CreateObject<EthernetNetDevice>();
swnet0->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n3->AddDevice(swnet0);
Names::Add("SW#01", swnet0);
Ptr<EthernetNetDevice> swnet1 = CreateObject<EthernetNetDevice>();
swnet1->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n3->AddDevice(swnet1);
Names::Add("SW#02", swnet1);
Ptr<EthernetNetDevice> swnet2 = CreateObject<EthernetNetDevice>();
swnet2->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n3->AddDevice(swnet2);
Names::Add("SW#03", swnet2);
[...]
//Create Ethernet Channels and connect switch to the end-stations
Ptr<EthernetChannel> channel0 = CreateObject<EthernetChannel>();
channel0->SetAttribute("Delay", TimeValue(NanoSeconds(50)));
net0->Attach(channel0);
swnet0->Attach(channel0);
Ptr<EthernetChannel> channel1 = CreateObject<EthernetChannel>();
channel1->SetAttribute("Delay", TimeValue(NanoSeconds(75)));
net1->Attach(channel1);
swnet1->Attach(channel1);
Ptr<EthernetChannel> channel2 = CreateObject<EthernetChannel>();
channel2->SetAttribute("Delay", TimeValue(NanoSeconds(100)));
net2->Attach(channel2);
swnet2->Attach(channel2);
[...]
//Create and add a switch net device to the switch node
Ptr<SwitchNetDevice> sw = CreateObject<SwitchNetDevice>();
sw->SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(2)));
sw->SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(5)));
n3->AddDevice(sw);
[...]
//Create 2 output port FIFOs for each netDevice.
for (int i=0; i<2; i++){
Ptr<DropTailQueue<Packet>> q0 = CreateObject<DropTailQueue<Packet>>();
q0->SetAttribute("MaxSize", QueueSizeValue(QueueSize("250p")));
net0->SetQueue(q0);
[...]
//Application description
//ES1 -> ES3 with priority 1
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
app0->Setup(net0);
app0->SetAttribute("Address", AddressValue(net2->GetAddress()));
app0->SetAttribute("BurstSize", UintegerValue(2));
app0->SetAttribute("PayloadSize", UintegerValue(1400));
app0->SetAttribute("Period", TimeValue(Seconds(5)));
app0->SetAttribute("InterFrame", TimeValue(MilliSeconds(20)));
app0->SetAttribute("Jitter", TimeValue(MilliSeconds(50)));
app0->SetAttribute("Offset", TimeValue(Seconds(1)));
app0->SetAttribute("VlanID", UintegerValue(1));
app0->SetAttribute("PCP", UintegerValue(1));
app0->SetAttribute("DEI", UintegerValue(0));
[...]
```
## Final simulation script
Here is the simulation script you should have at the end of this chapter.
```c++
#include "ns3/simulator.h"
#include "ns3/core-module.h"
#include "ns3/node.h"
#include "ns3/drop-tail-queue.h"
#include "ns3/ethernet-net-device.h"
#include "ns3/ethernet-channel.h"
#include "ns3/switch-net-device.h"
#include "ns3/ethernet-generator.h"
using namespace ns3;
NS_LOG_COMPONENT_DEFINE("Chapter 2");
//A callback to log the pkt emission
static void
MacTxCallback(std::string context, Ptr<const Packet> p)
{
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " sent!");
}
//A callback to log the pkt reception
static void
MacRxCallback(std::string context, Ptr<const Packet> p)
{
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " received!");
}
int
main(int argc, char* argv[])
{
//Enable logging
LogComponentEnable("Chapter 2", LOG_LEVEL_INFO);
//Create four nodes
Ptr<Node> n0 = CreateObject<Node>();
Names::Add("ES1", n0);
Ptr<Node> n1 = CreateObject<Node>();
Names::Add("ES2", n1);
Ptr<Node> n2 = CreateObject<Node>();
Names::Add("ES3", n2);
Ptr<Node> n3 = CreateObject<Node>();
Names::Add("SW", n3);
//Create and add a netDevice to each end-station node
Ptr<EthernetNetDevice> net0 = CreateObject<EthernetNetDevice>();
net0->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n0->AddDevice(net0);
Names::Add("ES1#01", net0);
Ptr<EthernetNetDevice> net1 = CreateObject<EthernetNetDevice>();
net1->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n1->AddDevice(net1);
Names::Add("ES2#01", net1);
Ptr<EthernetNetDevice> net2 = CreateObject<EthernetNetDevice>();
net2->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n2->AddDevice(net2);
Names::Add("ES3#01", net2);
//Create and add a netDevice to each switch port
Ptr<EthernetNetDevice> swnet0 = CreateObject<EthernetNetDevice>();
swnet0->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n3->AddDevice(swnet0);
Names::Add("SW#01", swnet0);
Ptr<EthernetNetDevice> swnet1 = CreateObject<EthernetNetDevice>();
swnet1->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n3->AddDevice(swnet1);
Names::Add("SW#02", swnet1);
Ptr<EthernetNetDevice> swnet2 = CreateObject<EthernetNetDevice>();
swnet2->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n3->AddDevice(swnet2);
Names::Add("SW#03", swnet2);
//Create Ethernet Channels and connect switch to the end-stations
Ptr<EthernetChannel> channel0 = CreateObject<EthernetChannel>();
channel0->SetAttribute("Delay", TimeValue(NanoSeconds(50)));
net0->Attach(channel0);
swnet0->Attach(channel0);
Ptr<EthernetChannel> channel1 = CreateObject<EthernetChannel>();
channel1->SetAttribute("Delay", TimeValue(NanoSeconds(75)));
net1->Attach(channel1);
swnet1->Attach(channel1);
Ptr<EthernetChannel> channel2 = CreateObject<EthernetChannel>();
channel2->SetAttribute("Delay", TimeValue(NanoSeconds(100)));
net2->Attach(channel2);
swnet2->Attach(channel2);
//Create and add a switch net device to the switch node
Ptr<SwitchNetDevice> sw = CreateObject<SwitchNetDevice>();
sw->SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(2)));
sw->SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(5)));
n3->AddDevice(sw);
sw->AddSwitchPort(swnet0);
sw->AddSwitchPort(swnet1);
sw->AddSwitchPort(swnet2);
//Allocate Mac addresses to the netDevices
net0->SetAddress(Mac48Address::Allocate());
net1->SetAddress(Mac48Address::Allocate());
net2->SetAddress(Mac48Address::Allocate());
sw->SetAddress(Mac48Address::Allocate());
//Create 2 output port FIFOs for each netDevice.
for (int i=0; i<2; i++){
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
swnet0->SetQueue(CreateObject<DropTailQueue<Packet>>());
swnet1->SetQueue(CreateObject<DropTailQueue<Packet>>());
swnet2->SetQueue(CreateObject<DropTailQueue<Packet>>());
}
//Add a forwarding table entry
sw->AddForwardingTableEntry(Mac48Address::ConvertFrom(net2->GetAddress()), 1, {swnet2});
//Application description
//ES1 -> ES3 with priority 1
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
app0->Setup(net0);
app0->SetAttribute("Address", AddressValue(net2->GetAddress()));
app0->SetAttribute("BurstSize", UintegerValue(2));
app0->SetAttribute("PayloadSize", UintegerValue(1400));
app0->SetAttribute("Period", TimeValue(Seconds(5)));
app0->SetAttribute("InterFrame", TimeValue(MilliSeconds(20)));
app0->SetAttribute("Jitter", TimeValue(MilliSeconds(50)));
app0->SetAttribute("Offset", TimeValue(Seconds(1)));
app0->SetAttribute("VlanID", UintegerValue(1));
app0->SetAttribute("PCP", UintegerValue(1));
app0->SetAttribute("DEI", UintegerValue(0));
n0->AddApplication(app0);
app0->SetStartTime(Seconds(0));
app0->SetStopTime(Seconds(10));
//Callback declarations
//Callback to display the packet sent log
std::string context = Names::FindName(n0) + ":" + Names::FindName(net0);
net0->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
//Callback to display the packet received log
context = Names::FindName(n2) + ":" + Names::FindName(net2);
net2->TraceConnectWithoutContext("MacRx", MakeBoundCallback(&MacRxCallback, context));
//Execute the simulation
NS_LOG_INFO("Start of the simulation");
Simulator::Stop(Seconds(10));
Simulator::Run();
Simulator::Destroy();
NS_LOG_INFO("End of the simulation");
return 0;
}
```

View File

@@ -0,0 +1,385 @@
# Creation of a simple ethernet network
## Introduction
To perform a simulation with ns-3, you need to write a C++ program that describes the simulation to be performed. In this chapter, we will create such a simulation script able to simulate an Ethernet network composed of one switch to which three end stations are connected.
## First simulation script
Let's start by creating a script that runs a 10-second simulation. To do this, create a file called chapter1.cc in the scratch folder located in the ns-3 folder. In this file, copy the following lines:
```c++
#include "ns3/simulator.h"
using namespace ns3;
NS_LOG_COMPONENT_DEFINE("Chapter 1");
int
main(int argc, char* argv[])
{
//Enable logging
LogComponentEnable("Chapter 1", LOG_LEVEL_INFO);
//Execute the simulation
NS_LOG_INFO("Start of the simulation");
Simulator::Stop(Seconds(10));
Simulator::Run();
Simulator::Destroy();
NS_LOG_INFO("End of the simulation");
return 0;
}
```
To run it, simply execute the following command from the folder where ns-3 is installed.
```console
./ns3 run scratch/chapter1.cc
```
Congratulations, you have run your first simulation with ns-3! However, this simulation does not simulate anything.
## Topology description
Before simulating our Ethernet network, we must first describe it. To do this, let's start by adding the necessary dependencies.
```c++
#include "ns3/simulator.h"
#include "ns3/core-module.h"
#include "ns3/node.h"
#include "ns3/drop-tail-queue.h"
#include "ns3/ethernet-net-device.h"
#include "ns3/ethernet-channel.h"
#include "ns3/switch-net-device.h"
[...]
```
Next, the topology is described as follows:
```c++
[...]
//Enable logging
LogComponentEnable("Chapter 1", LOG_LEVEL_INFO);
//Create four nodes
Ptr<Node> n0 = CreateObject<Node>();
Names::Add("ES1", n0);
Ptr<Node> n1 = CreateObject<Node>();
Names::Add("ES2", n1);
Ptr<Node> n2 = CreateObject<Node>();
Names::Add("ES3", n2);
Ptr<Node> n3 = CreateObject<Node>();
Names::Add("SW", n3);
//Create and add a netDevice to each end-station node
Ptr<EthernetNetDevice> net0 = CreateObject<EthernetNetDevice>();
n0->AddDevice(net0);
Names::Add("ES1#01", net0);
Ptr<EthernetNetDevice> net1 = CreateObject<EthernetNetDevice>();
n1->AddDevice(net1);
Names::Add("ES2#01", net1);
Ptr<EthernetNetDevice> net2 = CreateObject<EthernetNetDevice>();
n2->AddDevice(net2);
Names::Add("ES3#01", net2);
//Create and add a netDevice to each switch port
Ptr<EthernetNetDevice> swnet0 = CreateObject<EthernetNetDevice>();
n3->AddDevice(swnet0);
Names::Add("SW#01", swnet0);
Ptr<EthernetNetDevice> swnet1 = CreateObject<EthernetNetDevice>();
n3->AddDevice(swnet1);
Names::Add("SW#02", swnet1);
Ptr<EthernetNetDevice> swnet2 = CreateObject<EthernetNetDevice>();
n3->AddDevice(swnet2);
Names::Add("SW#03", swnet2);
//Create Ethernet Channels and connect switch to the end-stations
Ptr<EthernetChannel> channel0 = CreateObject<EthernetChannel>();
net0->Attach(channel0);
swnet0->Attach(channel0);
Ptr<EthernetChannel> channel1 = CreateObject<EthernetChannel>();
net1->Attach(channel1);
swnet1->Attach(channel1);
Ptr<EthernetChannel> channel2 = CreateObject<EthernetChannel>();
net2->Attach(channel2);
swnet2->Attach(channel2);
//Create and add a switch net device to the switch node
Ptr<SwitchNetDevice> sw = CreateObject<SwitchNetDevice>();
n3->AddDevice(sw);
sw->AddSwitchPort(swnet0);
sw->AddSwitchPort(swnet1);
sw->AddSwitchPort(swnet2);
//Allocate Mac addresses to the netDevices
net0->SetAddress(Mac48Address::Allocate());
net1->SetAddress(Mac48Address::Allocate());
net2->SetAddress(Mac48Address::Allocate());
sw->SetAddress(Mac48Address::Allocate());
//Create two output port FIFOs for each netDevice.
for (int i=0; i<2; i++){
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
swnet0->SetQueue(CreateObject<DropTailQueue<Packet>>());
swnet1->SetQueue(CreateObject<DropTailQueue<Packet>>());
swnet2->SetQueue(CreateObject<DropTailQueue<Packet>>());
}
[...]
```
In this code, the following six steps are performed:
1. *Creating nodes:* In this example, four nodes are created.
2. *Creating NetDevices:* A NetDevice is a network interface in ns-3 terminology. Here, one NetDevice is created and added to each end-station node, and three NetDevices are created and added to the switch node.
3. *Creating channels:* A channel is a link in ns-3 terminology in the case of the wired network considered here. Thus, three channels are created and attached to different NetDevices to connect the three end stations to the switch.
4. *Creating SwitchNetDevices:* The SwitchNetDevice is the object that will perform switching between the switch's NetDevices. Here, a SwitchNetDevice object is created and attached to the switch node. The switch ports are also attached to it.
5. *Allocation of Mac addresses:* For our example, four mac addresses are allocated using the iterator provided by ns-3.
6. *Creation of output port queues:* For our example, two FIFOs are instantiated per NetDevices.
At this stage, it is possible to run a simulation, but the output will be the same since no traffic is simulated.
## Traffic simulation
To send Ethernet frames in our network, we need to instantiate applications. To instantiate these applications, we must first add the following dependency.
```c++
#include “ns3/ethernet-generator.h”
```
This dependency is part of Eden-sim and is used to transmit Q-Tagged Ethernet frames.
Next, let's add an application that sends a burst of two frames with a payload of 1400 bytes, a priority of 1, and a VLAN ID of 1 every 5 seconds. This application is hosted on node ES1. The frames are destined for ES3. Here is the code used to instantiate such an application:
```c++
[...]
swnet2->SetQueue(CreateObject<DropTailQueue<Packet>>());
}
//Application description
//ES1 -> ES3 with priority 1
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
app0->Setup(net0);
app0->SetAttribute("Address", AddressValue(net2->GetAddress()));
app0->SetAttribute("BurstSize", UintegerValue(2));
app0->SetAttribute("PayloadSize", UintegerValue(1400));
app0->SetAttribute("Period", TimeValue(Seconds(5)));
app0->SetAttribute("VlanID", UintegerValue(1));
app0->SetAttribute("PCP", UintegerValue(1));
n0->AddApplication(app0);
app0->SetStartTime(Seconds(0));
app0->SetStopTime(Seconds(10));
[...]
```
With this simulation script complete, you can run a simulation... And you should see nothing new.
Indeed, there is no indication for ns-3 to produce any output. So our frames are sent in our simulated network, but we have no output to confirm it. To display logs about our frames in the console, let's add a callback for the transmission and one for the reception.
```c++
[...]
NS_LOG_COMPONENT_DEFINE("Chapter 1");
//A callback to log the pkt emission
static void
MacTxCallback(std::string context, Ptr<const Packet> p)
{
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " sent!");
}
//A callback to log the pkt reception
static void
MacRxCallback(std::string context, Ptr<const Packet> p)
{
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " received!");
}
[...]
```
```c++
[...]
app0->SetStopTime(Seconds(10));
//Callback declarations
//Callback to display the packet sent log
std::string context = Names::FindName(n0) + ":" + Names::FindName(net0);
net0->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
//Callback to display the packet received log
context = Names::FindName(n2) + ":" + Names::FindName(net2);
net2->TraceConnectWithoutContext("MacRx", MakeBoundCallback(&MacRxCallback, context));
[...]
```
If you run the simulation again, you should get the following output.
```console
$ ./ns3 run scratch/book.cc
[0/2] Re-checking globbed directories...
[2/2] Linking CXX executable ../build/scratch/ns3.40-book-default
Start of the simulation
+0s ES1:ES1#01 : Pkt #0 sent!
+0s ES1:ES1#01 : Pkt #1 sent!
+5s ES1:ES1#01 : Pkt #2 sent!
+5s ES1:ES1#01 : Pkt #3 sent!
End of the simulation
```
We can see that four frames are successfully sent by ES1 but are never received by ES3. This is because, after the first hop, the frames are received by the switch but it does not know which port to send them to. It is therefore necessary to add a static forwarding configuration to our switch.
## Network configuration
Unlike plug-and-play switches, the switches simulated by Eden-sim are designed for critical embedded networks. To guarantee network determinism, these switches do not implement dynamic mechanisms such as mac learning. They must therefore be configured statically before the simulation begins.
Here, the only configuration missing to transmit frames to ES3 is the configuration of the static switching table. It is possible to add an entry to this table as follows:
```c++
[...]
swnet2->SetQueue(CreateObject<DropTailQueue<Packet>>());
}
//Add a forwarding table entry
sw->AddForwardingTableEntry(Mac48Address::ConvertFrom(net2->GetAddress()), 1, {swnet2});
[...]
```
After this configuration, running the simulation produces the following output, which finally indicates the transmission and reception of frames.
```console
$ ./ns3 run scratch/book.cc
[0/2] Re-checking globbed directories...
[2/2] Linking CXX executable ../build/scratch/ns3.40-book-default
Start of the simulation
+0s ES1:ES1#01 : Pkt #0 sent!
+0s ES1:ES1#01 : Pkt #1 sent!
+2.293e-05s ES3:ES3#01 : Pkt #0 received!
+3.4466e-05s ES3:ES3#01 : Pkt #1 received!
+5s ES1:ES1#01 : Pkt #2 sent!
+5s ES1:ES1#01 : Pkt #3 sent!
+5.00002s ES3:ES3#01 : Pkt #2 received!
+5.00003s ES3:ES3#01 : Pkt #3 received!
End of the simulation
```
## Final simulation script
Here is the simulation script you should have at the end of this chapter.
```c++
#include "ns3/simulator.h"
#include "ns3/core-module.h"
#include "ns3/node.h"
#include "ns3/drop-tail-queue.h"
#include "ns3/ethernet-net-device.h"
#include "ns3/ethernet-channel.h"
#include "ns3/switch-net-device.h"
#include "ns3/ethernet-generator.h"
using namespace ns3;
NS_LOG_COMPONENT_DEFINE("Chapter 1");
//A callback to log the pkt emission
static void
MacTxCallback(std::string context, Ptr<const Packet> p)
{
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " sent!");
}
//A callback to log the pkt reception
static void
MacRxCallback(std::string context, Ptr<const Packet> p)
{
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " received!");
}
int
main(int argc, char* argv[])
{
//Enable logging
LogComponentEnable("Chapter 1", LOG_LEVEL_INFO);
//Create four nodes
Ptr<Node> n0 = CreateObject<Node>();
Names::Add("ES1", n0);
Ptr<Node> n1 = CreateObject<Node>();
Names::Add("ES2", n1);
Ptr<Node> n2 = CreateObject<Node>();
Names::Add("ES3", n2);
Ptr<Node> n3 = CreateObject<Node>();
Names::Add("SW", n3);
//Create and add a netDevice to each end-station node
Ptr<EthernetNetDevice> net0 = CreateObject<EthernetNetDevice>();
n0->AddDevice(net0);
Names::Add("ES1#01", net0);
Ptr<EthernetNetDevice> net1 = CreateObject<EthernetNetDevice>();
n1->AddDevice(net1);
Names::Add("ES2#01", net1);
Ptr<EthernetNetDevice> net2 = CreateObject<EthernetNetDevice>();
n2->AddDevice(net2);
Names::Add("ES3#01", net2);
//Create and add a netDevice to each switch port
Ptr<EthernetNetDevice> swnet0 = CreateObject<EthernetNetDevice>();
n3->AddDevice(swnet0);
Names::Add("SW#01", swnet0);
Ptr<EthernetNetDevice> swnet1 = CreateObject<EthernetNetDevice>();
n3->AddDevice(swnet1);
Names::Add("SW#02", swnet1);
Ptr<EthernetNetDevice> swnet2 = CreateObject<EthernetNetDevice>();
n3->AddDevice(swnet2);
Names::Add("SW#03", swnet2);
//Create Ethernet Channels and connect switch to the end-stations
Ptr<EthernetChannel> channel0 = CreateObject<EthernetChannel>();
net0->Attach(channel0);
swnet0->Attach(channel0);
Ptr<EthernetChannel> channel1 = CreateObject<EthernetChannel>();
net1->Attach(channel1);
swnet1->Attach(channel1);
Ptr<EthernetChannel> channel2 = CreateObject<EthernetChannel>();
net2->Attach(channel2);
swnet2->Attach(channel2);
//Create and add a switch net device to the switch node
Ptr<SwitchNetDevice> sw = CreateObject<SwitchNetDevice>();
n3->AddDevice(sw);
sw->AddSwitchPort(swnet0);
sw->AddSwitchPort(swnet1);
sw->AddSwitchPort(swnet2);
//Allocate Mac addresses to the netDevices
net0->SetAddress(Mac48Address::Allocate());
net1->SetAddress(Mac48Address::Allocate());
net2->SetAddress(Mac48Address::Allocate());
sw->SetAddress(Mac48Address::Allocate());
//Create 2 output port FIFOs for each netDevice.
for (int i=0; i<2; i++){
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
swnet0->SetQueue(CreateObject<DropTailQueue<Packet>>());
swnet1->SetQueue(CreateObject<DropTailQueue<Packet>>());
swnet2->SetQueue(CreateObject<DropTailQueue<Packet>>());
}
//Add a forwarding table entry
sw->AddForwardingTableEntry(Mac48Address::ConvertFrom(net2->GetAddress()), 1, {swnet2});
//Application description
//ES1 -> ES3 with priority 1
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
app0->Setup(net0);
app0->SetAttribute("Address", AddressValue(net2->GetAddress()));
app0->SetAttribute("BurstSize", UintegerValue(2));
app0->SetAttribute("PayloadSize", UintegerValue(1400));
app0->SetAttribute("Period", TimeValue(Seconds(5)));
app0->SetAttribute("VlanID", UintegerValue(1));
app0->SetAttribute("PCP", UintegerValue(1));
n0->AddApplication(app0);
app0->SetStartTime(Seconds(0));
app0->SetStopTime(Seconds(10));
//Callback declarations
//Callback to display the packet sent log
std::string context = Names::FindName(n0) + ":" + Names::FindName(net0);
net0->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
//Callback to display the packet received log
context = Names::FindName(n2) + ":" + Names::FindName(net2);
net2->TraceConnectWithoutContext("MacRx", MakeBoundCallback(&MacRxCallback, context));
//Execute the simulation
NS_LOG_INFO("Start of the simulation");
Simulator::Stop(Seconds(10));
Simulator::Run();
Simulator::Destroy();
NS_LOG_INFO("End of the simulation");
return 0;
}
```

View File

@@ -0,0 +1,740 @@
# Creation of a simple tsn network
## Introduction
In this chapter, we will explore how to transform the Ethernet network simulation script from the previous chapter into a TSN network simulation script. Then, we will discuss how to instantiate and configure the various TSN mechanisms supported by the simulation library.
Note that the operation and configuration of TSN mechanisms will not be explained in depth. This chapter assumes that the reader is familiar with the details of the mechanisms implemented.
## From Ethernet to TSN simulation
Let's start by importing two new objects: TsnNode and TsnNetDevice.
```c++
[...]
#include "ns3/tsn-node.h"
#include "ns3/tsn-net-device.h"
[...]
```
Next, it is necessary to replace the node and EthernetNetDevice objects with their TSN versions in order to instantiate the various TSN mechanisms described below.
```c++
[...]
//Create four nodes
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
Names::Add("ES1", n0);
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
Names::Add("ES2", n1);
Ptr<TsnNode> n2 = CreateObject<TsnNode>();
Names::Add("ES3", n2);
Ptr<TsnNode> n3 = CreateObject<TsnNode>();
Names::Add("SW", n3);
//Create and add a netDevice to each end-station node
Ptr<TsnNetDevice> net0 = CreateObject<TsnNetDevice>();
n0->AddDevice(net0);
Names::Add("ES1#01", net0);
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
n1->AddDevice(net1);
Names::Add("ES2#01", net1);
Ptr<TsnNetDevice> net2 = CreateObject<TsnNetDevice>();
n2->AddDevice(net2);
Names::Add("ES3#01", net2);
//Create and add a netDevice to each switch port
Ptr<TsnNetDevice> swnet0 = CreateObject<TsnNetDevice>();
n3->AddDevice(swnet0);
Names::Add("SW#01", swnet0);
Ptr<TsnNetDevice> swnet1 = CreateObject<TsnNetDevice>();
n3->AddDevice(swnet1);
Names::Add("SW#02", swnet1);
Ptr<TsnNetDevice> swnet2 = CreateObject<TsnNetDevice>();
n3->AddDevice(swnet2);
Names::Add("SW#03", swnet2);
[...]
```
At this stage, it is possible to run a simulation, but the result will be identical to a simple Ethernet network.
To simplify the illustration of the latency control mechanisms (CBS and TAS), we can make the following modifications to the application:
```c++
[...]
//Application description
//ES1 -> ES3 with priority 1
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
app0->Setup(net0);
app0->SetAttribute("Address", AddressValue(net2->GetAddress()));
app0->SetAttribute("BurstSize", UintegerValue(5));
app0->SetAttribute("PayloadSize", UintegerValue(1400));
app0->SetAttribute("Period", TimeValue(Seconds(5)));
app0->SetAttribute("VlanID", UintegerValue(1));
app0->SetAttribute("PCP", UintegerValue(1));
n0->AddApplication(app0);
app0->SetStartTime(Seconds(0));
app0->SetStopTime(Seconds(10));
[...]
```
The output of a simulation should look like this:
```console
[0/2] Re-checking globbed directories...
[2/2] Linking CXX executable ../build/scratch/ns3.40-book-default
Start of the simulation
+0s ES1:ES1#01 : Pkt #0 sent!
+0s ES1:ES1#01 : Pkt #1 sent!
+0s ES1:ES1#01 : Pkt #2 sent!
+0s ES1:ES1#01 : Pkt #3 sent!
+0s ES1:ES1#01 : Pkt #4 sent!
+0.000233905s ES3:ES3#01 : Pkt #0 received!
+0.000349265s ES3:ES3#01 : Pkt #1 received!
+0.000464625s ES3:ES3#01 : Pkt #2 received!
+0.000579985s ES3:ES3#01 : Pkt #3 received!
+0.000695345s ES3:ES3#01 : Pkt #4 received!
+5s ES1:ES1#01 : Pkt #5 sent!
+5s ES1:ES1#01 : Pkt #6 sent!
+5s ES1:ES1#01 : Pkt #7 sent!
+5s ES1:ES1#01 : Pkt #8 sent!
+5s ES1:ES1#01 : Pkt #9 sent!
+5.00023s ES3:ES3#01 : Pkt #5 received!
+5.00035s ES3:ES3#01 : Pkt #6 received!
+5.00046s ES3:ES3#01 : Pkt #7 received!
+5.00058s ES3:ES3#01 : Pkt #8 received!
+5.0007s ES3:ES3#01 : Pkt #9 received!
End of the simulation
```
## CBS
To instantiate a CBS, we must first add its dependency.
```c++
#include "ns3/cbs.h"
```
It is then possible to instantiate a CBS and link it to an output port queue. In the following example, we instantiate the CBS on the output port of the transmitting end station.
```c++
[...]
//Create 2 output port FIFOs for each netDevice.
Ptr<Cbs> cbs = CreateObject<Cbs>();
cbs->SetTsnNetDevice(net0);
cbs->SetAttribute("IdleSlope", DataRateValue(DataRate("20Kb/s")));
cbs->SetAttribute("portTransmitRate", DataRateValue(DataRate("100Mb/s")));
net0->SetQueue(CreateObject<DropTailQueue<Packet>>()); //FIFO 0
net0->SetQueue(CreateObject<DropTailQueue<Packet>>(), cbs); //FIFO 1
for (int i=0; i<2; i++){
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
swnet0->SetQueue(CreateObject<DropTailQueue<Packet>>());
swnet1->SetQueue(CreateObject<DropTailQueue<Packet>>());
swnet2->SetQueue(CreateObject<DropTailQueue<Packet>>());
}
[...]
```
When launching the simulation, we can now see that the reception of burst frames is spread out over time due to the waiting time imposed by the CBS credit reload on the emission port.
```console
[0/2] Re-checking globbed directories...
[2/2] Linking CXX executable ../build/scratch/ns3.40-book-default
Start of the simulation
+0s ES1:ES1#01 : Pkt #0 sent!
+0s ES1:ES1#01 : Pkt #1 sent!
+0s ES1:ES1#01 : Pkt #2 sent!
+0s ES1:ES1#01 : Pkt #3 sent!
+0s ES1:ES1#01 : Pkt #4 sent!
+0.000233905s ES3:ES3#01 : Pkt #0 received!
+0.577031s ES3:ES3#01 : Pkt #1 received!
+1.15383s ES3:ES3#01 : Pkt #2 received!
+1.73063s ES3:ES3#01 : Pkt #3 received!
+2.30743s ES3:ES3#01 : Pkt #4 received!
+5s ES1:ES1#01 : Pkt #5 sent!
+5s ES1:ES1#01 : Pkt #6 sent!
+5s ES1:ES1#01 : Pkt #7 sent!
+5s ES1:ES1#01 : Pkt #8 sent!
+5s ES1:ES1#01 : Pkt #9 sent!
+5.00023s ES3:ES3#01 : Pkt #5 received!
+5.57703s ES3:ES3#01 : Pkt #6 received!
+6.15383s ES3:ES3#01 : Pkt #7 received!
+6.73063s ES3:ES3#01 : Pkt #8 received!
+7.30743s ES3:ES3#01 : Pkt #9 received!
End of the simulation
```
## TAS
To instanciate TAS, we need to add a clock to the TsnNode, add GCL entries to the net device and add 8 FIFOs to the output ports. It can be done as follows:
```c++
[...]
//Add a perfect clock to the SW node
n3->AddClock(CreateObject<Clock>());
[...]
//Create 8 output port FIFOs for each netDevice.
Ptr<Cbs> cbs = CreateObject<Cbs>();
cbs->SetTsnNetDevice(net0);
cbs->SetAttribute("IdleSlope", DataRateValue(DataRate("20Kb/s")));
cbs->SetAttribute("portTransmitRate", DataRateValue(DataRate("100Mb/s")));
net0->SetQueue(CreateObject<DropTailQueue<Packet>>()); //FIFO 0
net0->SetQueue(CreateObject<DropTailQueue<Packet>>(), cbs); //FIFO 1
for (int i=0; i<6; i++){
net0->SetQueue(CreateObject<DropTailQueue<Packet>>()); //FIFO 0
}
for (int i=0; i<8; i++){
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
swnet0->SetQueue(CreateObject<DropTailQueue<Packet>>());
swnet1->SetQueue(CreateObject<DropTailQueue<Packet>>());
swnet2->SetQueue(CreateObject<DropTailQueue<Packet>>());
}
[...]
//Configure TAS schedule
swnet2->AddGclEntry(Time(Seconds(2)), 0); //All gates are close
swnet2->AddGclEntry(Time(Seconds(3)), 2); //Only the gate of the FIFO 1 is open
swnet2->StartTas();
[...]
```
In this example, a TAS schedule is added to the switch's output port, used by the flow. This schedule is designed to delay the frames of the two bursts by approximately two seconds compared to the previous example. The result obtained is as follows.
```console
[0/2] Re-checking globbed directories...
[2/2] Linking CXX executable ../build/scratch/ns3.40-book-default
Start of the simulation
+0s ES1:ES1#01 : Pkt #0 sent!
+0s ES1:ES1#01 : Pkt #1 sent!
+0s ES1:ES1#01 : Pkt #2 sent!
+0s ES1:ES1#01 : Pkt #3 sent!
+0s ES1:ES1#01 : Pkt #4 sent!
+2.00011s ES3:ES3#01 : Pkt #0 received!
+2.00023s ES3:ES3#01 : Pkt #1 received!
+2.00035s ES3:ES3#01 : Pkt #2 received!
+2.00046s ES3:ES3#01 : Pkt #3 received!
+2.30743s ES3:ES3#01 : Pkt #4 received!
+5s ES1:ES1#01 : Pkt #5 sent!
+5s ES1:ES1#01 : Pkt #6 sent!
+5s ES1:ES1#01 : Pkt #7 sent!
+5s ES1:ES1#01 : Pkt #8 sent!
+5s ES1:ES1#01 : Pkt #9 sent!
+7.00011s ES3:ES3#01 : Pkt #5 received!
+7.00023s ES3:ES3#01 : Pkt #6 received!
+7.00035s ES3:ES3#01 : Pkt #7 received!
+7.00046s ES3:ES3#01 : Pkt #8 received!
+7.30743s ES3:ES3#01 : Pkt #9 received!
End of the simulation
```
## gPTP
To synchronize the nodes in our network using gPTP, several changes must be made. Let's start with the includes.
```c++
[...]
#include "ns3/clock-constant-drift.h"
#include "ns3/gPTP.h"
#include "ns3/ethernet-header2.h"
[...]
```
Next, let's modify the callbacks that log packet transmission and reception so that events are only logged if the VLAN ID matches the VLAN ID of the flows going from ES1 to ES3. This change prevents the output from being flooded with logs concerning the transmission or reception of synchronization frames. We also add a callback to log the difference between the perfect clock (the simulation time) and the device clock after each correction to verify that gPTP is working properly.
```c++
//A callback to log the pkt emission
static void
MacTxCallback(std::string context, Ptr<const Packet> p)
{
Ptr<Packet> pkt = p->Copy();
EthernetHeader2 ethHeader;
pkt->RemoveHeader(ethHeader);
if (ethHeader.GetVid() == 1) {
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " sent!");
}
}
//A callback to log the pkt reception
static void
MacRxCallback(std::string context, Ptr<const Packet> p)
{
Ptr<Packet> pkt = p->Copy();
EthernetHeader2 ethHeader;
pkt->RemoveHeader(ethHeader);
if (ethHeader.GetVid() == 1) {
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " received!");
}
}
//A callback to log clock offset after correction
static void
ClockAfterCorrectionCallback(std::string context, Time clockValue)
{
NS_LOG_INFO("[GPTP] At " << Simulator::Now() << " on "<< context << " clock value after correction = " << clockValue.GetNanoSeconds() << "ns (error = "<< (Simulator::Now()-clockValue).GetNanoSeconds() << "ns)");
}
```
Next, we replace the perfect clock previously instantiated on n3(SW) in the TAS section with clock instantiation on the various network devices. Note that the clock instantiated on ES1(n0) is a perfect clock (i.e., it corresponds to the simulation time) since it acts as the Grandmaster.
```c++
[...]
Ptr<TsnNode> n3 = CreateObject<TsnNode>();
Names::Add("SW", n3);
//Create and add clocks to TsnNodes
Ptr<Clock> c0 = CreateObject<Clock>(); //perfect clock because Grandmaster
n0->SetMainClock(c0);
Ptr<ConstantDriftClock> c1 = CreateObject<ConstantDriftClock>();
c1->SetAttribute("InitialOffset", TimeValue(Seconds(20)));
c1->SetAttribute("DriftRate", DoubleValue(-50));
c1->SetAttribute("Granularity", TimeValue(NanoSeconds(10)));
n1->SetMainClock(c1);
Ptr<ConstantDriftClock> c2 = CreateObject<ConstantDriftClock>();
c2->SetAttribute("InitialOffset", TimeValue(Seconds(3)));
c2->SetAttribute("DriftRate", DoubleValue(2));
c2->SetAttribute("Granularity", TimeValue(NanoSeconds(10)));
n2->SetMainClock(c2);
Ptr<ConstantDriftClock> c3 = CreateObject<ConstantDriftClock>();
c3->SetAttribute("InitialOffset", TimeValue(Seconds(0.5)));
c3->SetAttribute("DriftRate", DoubleValue(-25));
c3->SetAttribute("Granularity", TimeValue(NanoSeconds(10)));
n3->SetMainClock(c3);
[...]
```
Then, we add and configure the gPTP instances on the different nodes. Note that the implementation of gPTP in Eden-sim only supports static configuration of gPTP (i.e. no BTCA).
```c++
[...]
swnet2->SetQueue(CreateObject<DropTailQueue<Packet>>());
}
Ptr<GPTP> gPTP0 = CreateObject<GPTP>();
gPTP0->SetNode(n0);
gPTP0->SetMainClock(c0);
gPTP0->AddDomain(0);
gPTP0->AddPort(net0, GPTP::MASTER, 0);
gPTP0->SetAttribute("SyncInterval", TimeValue(Seconds(0.125))); //This line is not mandatory because 0.125s is the default value
gPTP0->SetAttribute("PdelayInterval", TimeValue(Seconds(1))); //This line is not mandatory because 1s is the default value
gPTP0->SetAttribute("Priority", UintegerValue(7));
n0->AddApplication(gPTP0);
gPTP0->SetStartTime(Seconds(0));
Ptr<GPTP> gPTP1 = CreateObject<GPTP>();
gPTP1->SetNode(n1);
gPTP1->SetMainClock(c1);
gPTP1->AddDomain(0);
gPTP1->AddPort(net1, GPTP::SLAVE, 0);
gPTP1->SetAttribute("Priority", UintegerValue(7));
n1->AddApplication(gPTP1);
gPTP1->SetStartTime(Seconds(0));
Ptr<GPTP> gPTP2 = CreateObject<GPTP>();
gPTP2->SetNode(n2);
gPTP2->SetMainClock(c2);
gPTP2->AddDomain(0);
gPTP2->AddPort(net2, GPTP::SLAVE, 0);
gPTP2->SetAttribute("Priority", UintegerValue(7));
n2->AddApplication(gPTP2);
gPTP2->SetStartTime(Seconds(0));
Ptr<GPTP> gPTP3 = CreateObject<GPTP>();
gPTP3->SetNode(n3);
gPTP3->SetMainClock(c3);
gPTP3->AddDomain(0);
gPTP3->AddPort(swnet0, GPTP::SLAVE, 0);
gPTP3->AddPort(swnet1, GPTP::MASTER, 0);
gPTP3->AddPort(swnet2, GPTP::MASTER, 0);
gPTP3->SetAttribute("Priority", UintegerValue(7));
n3->AddApplication(gPTP3);
gPTP3->SetStartTime(Seconds(0));
```
And finally, we add the callbacks.
```c++
[...]
net2->TraceConnectWithoutContext("MacRx", MakeBoundCallback(&MacRxCallback, context));
//Callback to display clock offset after correction
gPTP1->TraceConnectWithoutContext("ClockAfterCorrection", MakeBoundCallback(&ClockAfterCorrectionCallback, Names::FindName(n1)));
gPTP2->TraceConnectWithoutContext("ClockAfterCorrection", MakeBoundCallback(&ClockAfterCorrectionCallback, Names::FindName(n2)));
gPTP3->TraceConnectWithoutContext("ClockAfterCorrection", MakeBoundCallback(&ClockAfterCorrectionCallback, Names::FindName(n3)));
[...]
```
When running the simulation, we can observe that gPTP effectively mitigates clock drift thanks to periodic synchronization on SW and ES2. However, we note that there is no gPTP log for ES3. This is due to the TAS configuration, which never opens the FIFO7 gate used by synchronization messages. Of course, such a configuration has no place in a network that is intended to be functional, but in this example it illustrates the impact of the TAS configuration on gPTP packets.
## Stream Identification
Before using PSFP or FRER, it is necessary to implement an identification function. In this section, we will use a null Stream identification function on the switch port connected to ES1. This function will then be used in the following two sections to implement PSFP in order to validate the flow contract and to replicate frames using FRER.
Let's start by importing this function.
```c++
[...]
#include "ns3/stream-identification-function-null.h"
[...]
```
Next, let's create and add the identification function on port swnet0 in input and outfacing mode.
```c++
[...]
swnet2->StartTas();
//Add a stream identification function
Ptr<NullStreamIdentificationFunction> sif0 = CreateObject<NullStreamIdentificationFunction>();
uint16_t StreamHandle = 10;
sif0->SetAttribute("VlanID", UintegerValue(1));
sif0->SetAttribute("Address", AddressValue(net2->GetAddress()));
n3->AddStreamIdentificationFunction(StreamHandle, sif0, {swnet0}, {}, {}, {});
[...]
```
## PSFP
Now that we have an identification function capable of identifying frames going from ES1 to ES3 with VLAN ID 1, we can set up a PSFP instance to validate compliance with a network usage contract. Currently, the simulator implements the stream filter and the flow meter. They can be added and configured as follows.
```c++
[...]
n3->AddStreamIdentificationFunction(StreamHandle, sif0, {swnet0}, {}, {}, {});
//PSFP configuration
Ptr<StreamFilterInstance> sfi0 = CreateObject<StreamFilterInstance>();
sfi0->SetAttribute("StreamHandle", IntegerValue(StreamHandle));
sfi0->SetAttribute("Priority", IntegerValue(-1)); //-1 = wildcard
sfi0->SetAttribute("MaxSDUSize", UintegerValue(1422));
n3->AddStreamFilter(sfi0);
Ptr<FlowMeterInstance> fm0 = CreateObject<FlowMeterInstance>();
fm0->SetAttribute("CIR", DataRateValue(DataRate("20Kb/s")));
fm0->SetAttribute("CBS", UintegerValue(1400));
fm0->SetAttribute("DropOnYellow", BooleanValue(true));
fm0->SetAttribute("MarkAllFramesRedEnable", BooleanValue(false));
uint16_t fmid = n3->AddFlowMeter(fm0);
sfi0->AddFlowMeterInstanceId(fmid);
[...]
```
After these changes, running the simulation does not produce a different output from previous runs. However, by changing the parameters of the emitting application to increase its bandwidth consumption (e.g., increasing the packet size) or by increasing the idle slope of the CBS, it is possible to observe that packets that do not comply with the contract are never received as they are discarded.
## FRER
And finally, let's instantiate FRER. However, the topology we are working with in this chapter does not have multiple paths between ES1 and ES3. So in this section, we will replicate the frames on the output ports of the switch connected to ES2 and ES3 to illustrate the philosophy behind FRER instantiation. We will only detail the replication part. The elimination part is detailed in the example contrib/tsn/examples/tsn-switched-withFRER.cc, which has a topology much more suited to the use of FRER.
Replication with FRER is based on two functions: Sequence Generation Function and Sequence Encode/Decode Function. These two functions are created and configured as follows.
```c++
[...]
sfi0->AddFlowMeterInstanceId(fmid);
//Sequencing : Sequence generation
Ptr<SequenceGenerationFunction> seqf0 = CreateObject<SequenceGenerationFunction>();
seqf0->SetAttribute("Direction", BooleanValue(false)); //in-facing
seqf0->SetStreamHandle({StreamHandle});
n3->AddSequenceGenerationFunction(seqf0);
//Sequence encode
Ptr<SequenceEncodeDecodeFunction> seqEnc0 = CreateObject<SequenceEncodeDecodeFunction>();
seqEnc0->SetAttribute("Direction", BooleanValue(false)); //in-facing
seqEnc0->SetAttribute("Active", BooleanValue(true));
seqEnc0->SetStreamHandle({StreamHandle});
seqEnc0->SetPort(swnet0);
n3->AddSequenceEncodeDecodeFunction(seqEnc0);
//Add a forwarding table entry
sw->AddForwardingTableEntry(Mac48Address::ConvertFrom(net2->GetAddress()), 1, {swnet1, swnet2});
[...]
```
With this configuration, replication is achieved by forwarding to two different ports. This simplifies configuration by not using the FRER splitting function. However, it is necessary to change the configuration of the forwarding table as shown in the previous listing.
In order to validate the correct operation of the replication (i.e., the addition of the R-TAG), modify the callbacks as follows to display the frame size at transmission and reception.
```c++
[...]
//A callback to log the pkt emission
static void
MacTxCallback(std::string context, Ptr<const Packet> p)
{
Ptr<Packet> pkt = p->Copy();
EthernetHeader2 ethHeader;
pkt->RemoveHeader(ethHeader);
if (ethHeader.GetVid() == 1) {
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << "(" << p->GetSize() << "bytes) sent!");
}
}
//A callback to log the pkt reception
static void
MacRxCallback(std::string context, Ptr<const Packet> p)
{
Ptr<Packet> pkt = p->Copy();
EthernetHeader2 ethHeader;
pkt->RemoveHeader(ethHeader);
if (ethHeader.GetVid() == 1) {
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << "(" << p->GetSize() << "bytes) received!");
}
}
[...]
```
And now, when running the simulation script, we observe an increase in frame size of 6 bytes (the size of R-TAG) between transmission and reception, as illustrated below.
```console
[...]
+5s ES1:ES1#01 : Pkt #215(1422bytes) sent!
[...]
+7.30743s ES3:ES3#01 : Pkt #215(1428bytes) received!
[...]
```
## Conclusion and final simulation script
In this section, we have implemented the various TSN mechanisms of Eden-sim.
Note that the examples found in contrib/tsn/examples/ illustrate more complicated configurations and implement different traces to log information about the mechanism's operation. These examples are a good means of further exploring the uses of these TSN mechanisms.
Here is the script at the end of this chapter:
```c++
#include "ns3/simulator.h"
#include "ns3/core-module.h"
#include "ns3/node.h"
#include "ns3/drop-tail-queue.h"
#include "ns3/tsn-node.h"
#include "ns3/tsn-net-device.h"
#include "ns3/cbs.h"
#include "ns3/ethernet-channel.h"
#include "ns3/switch-net-device.h"
#include "ns3/ethernet-generator.h"
#include "ns3/clock-constant-drift.h"
#include "ns3/gPTP.h"
#include "ns3/ethernet-header2.h"
#include "ns3/stream-identification-function-null.h"
using namespace ns3;
NS_LOG_COMPONENT_DEFINE("Chapter 3");
//A callback to log the pkt emission
static void
MacTxCallback(std::string context, Ptr<const Packet> p)
{
Ptr<Packet> pkt = p->Copy();
EthernetHeader2 ethHeader;
pkt->RemoveHeader(ethHeader);
if (ethHeader.GetVid() == 1) {
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << "(" << p->GetSize() << "bytes) sent!");
}
}
//A callback to log the pkt reception
static void
MacRxCallback(std::string context, Ptr<const Packet> p)
{
Ptr<Packet> pkt = p->Copy();
EthernetHeader2 ethHeader;
pkt->RemoveHeader(ethHeader);
if (ethHeader.GetVid() == 1) {
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << "(" << p->GetSize() << "bytes) received!");
}
}
//A callback to log clock offset after correction
static void
ClockAfterCorrectionCallback(std::string context, Time clockValue)
{
NS_LOG_INFO("[GPTP] At " << Simulator::Now() << " on "<< context << " clock value after correction = " << clockValue.GetNanoSeconds() << "ns (error = "<< (Simulator::Now()-clockValue).GetNanoSeconds() << "ns)");
}
int
main(int argc, char* argv[])
{
//Enable logging
LogComponentEnable("Chapter 3", LOG_LEVEL_INFO);
//Create four nodes
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
Names::Add("ES1", n0);
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
Names::Add("ES2", n1);
Ptr<TsnNode> n2 = CreateObject<TsnNode>();
Names::Add("ES3", n2);
Ptr<TsnNode> n3 = CreateObject<TsnNode>();
Names::Add("SW", n3);
//Create and add clocks to TsnNodes
Ptr<Clock> c0 = CreateObject<Clock>(); //perfect clock because Grandmaster
n0->SetMainClock(c0);
Ptr<ConstantDriftClock> c1 = CreateObject<ConstantDriftClock>();
c1->SetAttribute("InitialOffset", TimeValue(Seconds(20)));
c1->SetAttribute("DriftRate", DoubleValue(-50));
c1->SetAttribute("Granularity", TimeValue(NanoSeconds(10)));
n1->SetMainClock(c1);
Ptr<ConstantDriftClock> c2 = CreateObject<ConstantDriftClock>();
c2->SetAttribute("InitialOffset", TimeValue(Seconds(3)));
c2->SetAttribute("DriftRate", DoubleValue(2));
c2->SetAttribute("Granularity", TimeValue(NanoSeconds(10)));
n2->SetMainClock(c2);
Ptr<ConstantDriftClock> c3 = CreateObject<ConstantDriftClock>();
c3->SetAttribute("InitialOffset", TimeValue(Seconds(0.5)));
c3->SetAttribute("DriftRate", DoubleValue(-25));
c3->SetAttribute("Granularity", TimeValue(NanoSeconds(10)));
n3->SetMainClock(c3);
//Create and add a netDevice to each end-station node
Ptr<TsnNetDevice> net0 = CreateObject<TsnNetDevice>();
net0->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n0->AddDevice(net0);
Names::Add("ES1#01", net0);
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
net1->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n1->AddDevice(net1);
Names::Add("ES2#01", net1);
Ptr<TsnNetDevice> net2 = CreateObject<TsnNetDevice>();
net2->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n2->AddDevice(net2);
Names::Add("ES3#01", net2);
//Create and add a netDevice to each switch port
Ptr<TsnNetDevice> swnet0 = CreateObject<TsnNetDevice>();
swnet0->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n3->AddDevice(swnet0);
Names::Add("SW#01", swnet0);
Ptr<TsnNetDevice> swnet1 = CreateObject<TsnNetDevice>();
swnet1->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n3->AddDevice(swnet1);
Names::Add("SW#02", swnet1);
Ptr<TsnNetDevice> swnet2 = CreateObject<TsnNetDevice>();
swnet2->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
n3->AddDevice(swnet2);
Names::Add("SW#03", swnet2);
//Create Ethernet Channels and connect switch to the end-stations
Ptr<EthernetChannel> channel0 = CreateObject<EthernetChannel>();
channel0->SetAttribute("Delay", TimeValue(NanoSeconds(50)));
net0->Attach(channel0);
swnet0->Attach(channel0);
Ptr<EthernetChannel> channel1 = CreateObject<EthernetChannel>();
channel1->SetAttribute("Delay", TimeValue(NanoSeconds(75)));
net1->Attach(channel1);
swnet1->Attach(channel1);
Ptr<EthernetChannel> channel2 = CreateObject<EthernetChannel>();
channel2->SetAttribute("Delay", TimeValue(NanoSeconds(100)));
net2->Attach(channel2);
swnet2->Attach(channel2);
//Create and add a switch net device to the switch node
Ptr<SwitchNetDevice> sw = CreateObject<SwitchNetDevice>();
sw->SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(2)));
sw->SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(5)));
n3->AddDevice(sw);
sw->AddSwitchPort(swnet0);
sw->AddSwitchPort(swnet1);
sw->AddSwitchPort(swnet2);
//Allocate Mac addresses to the netDevices
net0->SetAddress(Mac48Address::Allocate());
net1->SetAddress(Mac48Address::Allocate());
net2->SetAddress(Mac48Address::Allocate());
sw->SetAddress(Mac48Address::Allocate());
//Create 8 output port FIFOs for each netDevice.
Ptr<Cbs> cbs = CreateObject<Cbs>();
cbs->SetTsnNetDevice(net0);
cbs->SetAttribute("IdleSlope", DataRateValue(DataRate("20Kb/s")));
cbs->SetAttribute("portTransmitRate", DataRateValue(DataRate("100Mb/s")));
net0->SetQueue(CreateObject<DropTailQueue<Packet>>()); //FIFO 0
net0->SetQueue(CreateObject<DropTailQueue<Packet>>(), cbs); //FIFO 1
for (int i=0; i<6; i++){
net0->SetQueue(CreateObject<DropTailQueue<Packet>>()); //FIFO 0
}
for (int i=0; i<8; i++){
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
swnet0->SetQueue(CreateObject<DropTailQueue<Packet>>());
swnet1->SetQueue(CreateObject<DropTailQueue<Packet>>());
swnet2->SetQueue(CreateObject<DropTailQueue<Packet>>());
}
//Add and configure gPTP
Ptr<GPTP> gPTP0 = CreateObject<GPTP>();
gPTP0->SetNode(n0);
gPTP0->SetMainClock(c0);
gPTP0->AddDomain(0);
gPTP0->AddPort(net0, GPTP::MASTER, 0);
gPTP0->SetAttribute("SyncInterval", TimeValue(Seconds(0.125))); //This line is not mandatory because 0.125s is the default value
gPTP0->SetAttribute("PdelayInterval", TimeValue(Seconds(1))); //This line is not mandatory because 1s is the default value
gPTP0->SetAttribute("Priority", UintegerValue(7));
n0->AddApplication(gPTP0);
gPTP0->SetStartTime(Seconds(0));
Ptr<GPTP> gPTP1 = CreateObject<GPTP>();
gPTP1->SetNode(n1);
gPTP1->SetMainClock(c1);
gPTP1->AddDomain(0);
gPTP1->AddPort(net1, GPTP::SLAVE, 0);
gPTP1->SetAttribute("Priority", UintegerValue(7));
n1->AddApplication(gPTP1);
gPTP1->SetStartTime(Seconds(0));
Ptr<GPTP> gPTP2 = CreateObject<GPTP>();
gPTP2->SetNode(n2);
gPTP2->SetMainClock(c2);
gPTP2->AddDomain(0);
gPTP2->AddPort(net2, GPTP::SLAVE, 0);
gPTP2->SetAttribute("Priority", UintegerValue(7));
n2->AddApplication(gPTP2);
gPTP2->SetStartTime(Seconds(0));
Ptr<GPTP> gPTP3 = CreateObject<GPTP>();
gPTP3->SetNode(n3);
gPTP3->SetMainClock(c3);
gPTP3->AddDomain(0);
gPTP3->AddPort(swnet0, GPTP::SLAVE, 0);
gPTP3->AddPort(swnet1, GPTP::MASTER, 0);
gPTP3->AddPort(swnet2, GPTP::MASTER, 0);
gPTP3->SetAttribute("Priority", UintegerValue(7));
n3->AddApplication(gPTP3);
gPTP3->SetStartTime(Seconds(0));
//Configure TAS schedule
swnet2->AddGclEntry(Time(Seconds(2)), 0); //All gates are close
swnet2->AddGclEntry(Time(Seconds(3)), 2); //Only the gate of the FIFO 1 is open
swnet2->StartTas();
//Add a stream identification function
Ptr<NullStreamIdentificationFunction> sif0 = CreateObject<NullStreamIdentificationFunction>();
uint16_t StreamHandle = 10;
sif0->SetAttribute("VlanID", UintegerValue(1));
sif0->SetAttribute("Address", AddressValue(net2->GetAddress()));
n3->AddStreamIdentificationFunction(StreamHandle, sif0, {swnet0}, {}, {}, {});
//PSFP configuration
Ptr<StreamFilterInstance> sfi0 = CreateObject<StreamFilterInstance>();
sfi0->SetAttribute("StreamHandle", IntegerValue(StreamHandle));
sfi0->SetAttribute("Priority", IntegerValue(-1)); //-1 = wildcard
sfi0->SetAttribute("MaxSDUSize", UintegerValue(1422));
n3->AddStreamFilter(sfi0);
Ptr<FlowMeterInstance> fm0 = CreateObject<FlowMeterInstance>();
fm0->SetAttribute("CIR", DataRateValue(DataRate("20Kb/s")));
fm0->SetAttribute("CBS", UintegerValue(1400));
fm0->SetAttribute("DropOnYellow", BooleanValue(true));
fm0->SetAttribute("MarkAllFramesRedEnable", BooleanValue(false));
uint16_t fmid = n3->AddFlowMeter(fm0);
sfi0->AddFlowMeterInstanceId(fmid);
//Sequencing : Sequence generation
Ptr<SequenceGenerationFunction> seqf0 = CreateObject<SequenceGenerationFunction>();
seqf0->SetAttribute("Direction", BooleanValue(false)); //in-facing
seqf0->SetStreamHandle({StreamHandle});
n3->AddSequenceGenerationFunction(seqf0);
//Sequence encode
Ptr<SequenceEncodeDecodeFunction> seqEnc0 = CreateObject<SequenceEncodeDecodeFunction>();
seqEnc0->SetAttribute("Direction", BooleanValue(false)); //in-facing
seqEnc0->SetAttribute("Active", BooleanValue(true));
seqEnc0->SetStreamHandle({StreamHandle});
seqEnc0->SetPort(swnet0);
n3->AddSequenceEncodeDecodeFunction(seqEnc0);
//Add a forwarding table entry
sw->AddForwardingTableEntry(Mac48Address::ConvertFrom(net2->GetAddress()), 1, {swnet1, swnet2});
//Application description
//ES1 -> ES3 with priority 1
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
app0->Setup(net0);
app0->SetAttribute("Address", AddressValue(net2->GetAddress()));
app0->SetAttribute("BurstSize", UintegerValue(5));
app0->SetAttribute("PayloadSize", UintegerValue(1400));
app0->SetAttribute("Period", TimeValue(Seconds(5)));
app0->SetAttribute("VlanID", UintegerValue(1));
app0->SetAttribute("PCP", UintegerValue(1));
n0->AddApplication(app0);
app0->SetStartTime(Seconds(0));
app0->SetStopTime(Seconds(10));
//Callback declarations
//Callback to display the packet sent log
std::string context = Names::FindName(n0) + ":" + Names::FindName(net0);
net0->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
//Callback to display the packet received log
context = Names::FindName(n2) + ":" + Names::FindName(net2);
net2->TraceConnectWithoutContext("MacRx", MakeBoundCallback(&MacRxCallback, context));
//Callback to display clock offset after correction
gPTP1->TraceConnectWithoutContext("ClockAfterCorrection", MakeBoundCallback(&ClockAfterCorrectionCallback, Names::FindName(n1)));
gPTP2->TraceConnectWithoutContext("ClockAfterCorrection", MakeBoundCallback(&ClockAfterCorrectionCallback, Names::FindName(n2)));
gPTP3->TraceConnectWithoutContext("ClockAfterCorrection", MakeBoundCallback(&ClockAfterCorrectionCallback, Names::FindName(n3)));
//Execute the simulation
NS_LOG_INFO("Start of the simulation");
Simulator::Stop(Seconds(10));
Simulator::Run();
Simulator::Destroy();
NS_LOG_INFO("End of the simulation");
return 0;
}
```

View File

@@ -0,0 +1,14 @@
# Introduction
Eden-sim is a ns-3 simulation library for embedded TSN networks.
This book is a user guide designed to assist in the creation of simulation scripts using Eden-sim. It is organised as follows:
- Getting started part to introduce the fundamental ideas of Eden-sim
- Advanced uses part for complex projects
Please note that in addition to the examples presented in this guide, example simulation scripts are also available in the following folders:
- contrib/ethernet/examples
- contrib/real-device/examples
- contrib/trace/examples
- contrib/traffic-generator/examples
- contrib/tsn/examples

View File

@@ -0,0 +1,3 @@
# Prerequisites
To put this guide into practice, you only need to have ns-3 and Eden-sim installed. The installation procedure for these two tools is described in Eden-sim's README.md.