diff --git a/mdsvex.config.js b/mdsvex.config.js index a720983..7a8c08d 100644 --- a/mdsvex.config.js +++ b/mdsvex.config.js @@ -3,6 +3,7 @@ import remarkGFM from 'remark-gfm'; import remarkEmoji from 'remark-emoji'; import rehypeSlug from 'rehype-slug'; import rehypeAutolinkHeadings from 'rehype-autolink-headings'; +import remarkFootnotes from 'remark-footnotes'; const config = defineConfig({ layout: { @@ -14,7 +15,7 @@ const config = defineConfig({ dashes: 'oldschool', }, - remarkPlugins: [remarkGFM, remarkEmoji], + remarkPlugins: [remarkGFM, remarkEmoji, remarkFootnotes], rehypePlugins: [rehypeSlug, rehypeAutolinkHeadings], }); diff --git a/package.json b/package.json index 51a442c..f6b4249 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "rehype-autolink-headings": "^6.1.1", "rehype-slug": "^5.0.1", "remark-emoji": "^3.0.2", + "remark-footnotes": "2.0", "remark-gfm": "^3.0.1", "svelte": "^3.44.0", "svelte-check": "^2.7.1", diff --git a/src/components/Code.svelte b/src/components/Code.svelte index 2823a61..ef5ff5c 100644 --- a/src/components/Code.svelte +++ b/src/components/Code.svelte @@ -58,4 +58,10 @@ :global([data-nu-scheme-is='dark'] body code) { color: var(--bg-color); } + :global(pre[class*='language-']) { + margin: 0.5em 1rem !important; + } + :global(code[class*='language-'], pre[class*='language-']) { + font-size: 0.9rem; + } diff --git a/src/components/Link.svelte b/src/components/Link.svelte index a00ea81..a50968b 100644 --- a/src/components/Link.svelte +++ b/src/components/Link.svelte @@ -23,15 +23,16 @@ } - (spin = true)} on:focus={() => (spin = true)} on:mouseleave={() => (spin = false)} > - {#if !disableIcon} - + {#if !disableIcon && !internal} + {/if} diff --git a/src/layouts/blog.svelte b/src/layouts/blog.svelte index 25a1640..1c612dc 100644 --- a/src/layouts/blog.svelte +++ b/src/layouts/blog.svelte @@ -1,8 +1,8 @@ + +For my thesis, I evaluated if containers are viable for low-latency networking. I +decided to pick LXC as my container implementation due to them being extremely +lightweight compared to its peers and also related work indicating, that LXC beats +others in raw performance. Latency-critical applications are typically +implemented with poll mode drivers in userspace, due to the traditional +interrupt-based network stack inducing unreliable delays[^1]. Unfortunately, +there are not a lot of tutorials out there on how to get DPDK to run with LXC. One resource that did help me, but is not complete and also is a bit older is from J. Krishnamurthy[^2]. + +## Prerequisites + +This tutorial expects that you went over the following checklist: + +- Debian Bullseye (other distributions should work too) +- a working LXC instance of at least LXC 4.0 (did not test earlier versions) +- a network interface for your containers so that they can communicate with the internet, and also you can SSH into the container +- another NIC that you want to use with DPDK + +## Host Setup + +We first must initialize the userspace device driver. There exist two kinds of +kernel modules that provide the driver interface: `igb_uio` and `vfio`. Since +the `vfio` module requires the IOMMU and the IOMMU can have - under some +circumstances - a bad impact on system performance, we opt for the `igb_uio` +module. A very interesting read about how the drivers work on a kernel level is +the paper of Koch[^3]. The following code installs the `igb_uio` kernel module. + +```bash +git clone http://dpdk.org/git/dpdk-kmods +cd dpdk-kmods/linux/igb_uio/ +make +modprobe uio +insmod igb_uio.ko +``` + +Next, clone whatever version of DPDK you want to use on your host. Do not +compile it! We will utilize the `dpdk-devbind` script from the provided usertools to bind a NIC to the driver `igb_uio`. This script can also be called with `--status` to verify if your NIC indeed was bound to the driver. Instead of eno8 in the following example, it is also possible to use the PCI identifier like 0000:65:00.0. + +```bash +git clone https://github.com/DPDK/dpdk.git +python dpdk/usertools/dpdk-devbind.py --bind=igb_uio eno8 +``` + +By binding the NIC to this driver, device files are created. These device files allow the userspace driver of DPDK to directly interact with the PCI device. The next example demonstrates how to find the device files and their major/minor IDs, which we need for the next step. In this case, the major ID is 239 and the minor ID is 0. + +```bash +$ ls /dev/uio* -la +crw------- 1 root root 239, 0 Jul 27 20:21 /dev/uio0 +``` + +Now we will pass through these device files to the container. Open the container config file under `/var/lib/lxc//config` and add following lines. The first two lines are required according to the lead developer of LXC Stéphane Graber[^4]. The third line gives access to the device with CGroups v2. And finally, we pass through the device file. The last line could also be replaced with a `mknode` call after starting the container, but I found this variant cleaner. + +```toml +lxc.mount.auto = +lxc.mount.auto = proc:rw sys:rw +lxc.cgroup2.devices.allow = c 239:0 rwm +lxc.mount.entry = /dev/uio0 dev/uio0 none bind,create=file +``` + +One last step is missing on the container host: the creation of hugepages. Modern CPUs with high core counts rely on multiple NUMA nodes, where each node has its memory. +Since I don't want to write more about the impact of suboptimal assigned memory, we create 2Mb hugepages for each node. + +```bash +echo 512 > /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages +echo 512 > /sys/devices/system/node/node1/hugepages/hugepages-2048kB/nr_hugepages +echo 512 > /sys/devices/system/node/node2/hugepages/hugepages-2048kB/nr_hugepages +... +``` + +Now we pass through the created device file to the container again. Open the container config file and add the following line. + +```toml +lxc.mount.entry = /dev/hugepages dev/hugepages none bind,create=dir 0 0 +``` + +The host is now set up and it should be possible to use your DPDK application in the container like you are used to it. In case multiple devices are bound to `igb_uio`, each container still sees the other devices even though they were not passed through. I assume this is because we mounted the `/sys` folder as well. While it throws a small warning in the DPDK application, it is no reason to be worried. + +Any questions? [Contact me!](/contact) + +
+ +[^1]: [5G QoS: Impact of Security Functions on Latency](https://www.net.in.tum.de/fileadmin/bibtex/publications/papers/gallenmueller_noms2020.pdf) +[^2]: http://mails.dpdk.org/archives/dev/2014-October/006373.html +[^3]: Koch, Hans J from Linutronix GmbH, 2013, "Userspace I/O drivers in a realtime context" +[^4]: https://github.com/lxc/lxd/issues/3619\#issuecomment-319430483 diff --git a/src/utils/one-dark.css b/src/utils/one-dark.css new file mode 100644 index 0000000..fc1d0e1 --- /dev/null +++ b/src/utils/one-dark.css @@ -0,0 +1,443 @@ +/** + * One Dark theme for prism.js + * Based on Atom's One Dark theme: https://github.com/atom/atom/tree/master/packages/one-dark-syntax + */ + +/** + * One Dark colours (accurate as of commit 8ae45ca on 6 Sep 2018) + * From colors.less + * --mono-1: hsl(220, 14%, 71%); + * --mono-2: hsl(220, 9%, 55%); + * --mono-3: hsl(220, 10%, 40%); + * --hue-1: hsl(187, 47%, 55%); + * --hue-2: hsl(207, 82%, 66%); + * --hue-3: hsl(286, 60%, 67%); + * --hue-4: hsl(95, 38%, 62%); + * --hue-5: hsl(355, 65%, 65%); + * --hue-5-2: hsl(5, 48%, 51%); + * --hue-6: hsl(29, 54%, 61%); + * --hue-6-2: hsl(39, 67%, 69%); + * --syntax-fg: hsl(220, 14%, 71%); + * --syntax-bg: hsl(220, 13%, 18%); + * --syntax-gutter: hsl(220, 14%, 45%); + * --syntax-guide: hsla(220, 14%, 71%, 0.15); + * --syntax-accent: hsl(220, 100%, 66%); + * From syntax-variables.less + * --syntax-selection-color: hsl(220, 13%, 28%); + * --syntax-gutter-background-color-selected: hsl(220, 13%, 26%); + * --syntax-cursor-line: hsla(220, 100%, 80%, 0.04); + */ + +code[class*='language-'], +pre[class*='language-'] { + background: hsl(220, 13%, 18%); + color: hsl(220, 14%, 71%); + text-shadow: 0 1px rgba(0, 0, 0, 0.3); + font-family: 'Fira Code', 'Fira Mono', Menlo, Consolas, 'DejaVu Sans Mono', monospace; + direction: ltr; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + line-height: 1.5; + -moz-tab-size: 2; + -o-tab-size: 2; + tab-size: 2; + -webkit-hyphens: none; + -moz-hyphens: none; + -ms-hyphens: none; + hyphens: none; +} + +/* Selection */ +code[class*='language-']::-moz-selection, +code[class*='language-'] *::-moz-selection, +pre[class*='language-'] *::-moz-selection { + background: hsl(220, 13%, 28%); + color: inherit; + text-shadow: none; +} + +code[class*='language-']::selection, +code[class*='language-'] *::selection, +pre[class*='language-'] *::selection { + background: hsl(220, 13%, 28%); + color: inherit; + text-shadow: none; +} + +/* Code blocks */ +pre[class*='language-'] { + padding: 1em; + margin: 0.5em 0; + overflow: auto; + border-radius: 0.3em; +} + +/* Inline code */ +:not(pre) > code[class*='language-'] { + padding: 0.2em 0.3em; + border-radius: 0.3em; + white-space: normal; +} + +/* Print */ +@media print { + code[class*='language-'], + pre[class*='language-'] { + text-shadow: none; + } +} + +.token.comment, +.token.prolog, +.token.cdata { + color: hsl(220, 10%, 40%); +} + +.token.doctype, +.token.punctuation, +.token.entity { + color: hsl(220, 14%, 71%); +} + +.token.attr-name, +.token.class-name, +.token.boolean, +.token.constant, +.token.number, +.token.atrule { + color: hsl(29, 54%, 61%); +} + +.token.keyword { + color: hsl(286, 60%, 67%); +} + +.token.property, +.token.tag, +.token.symbol, +.token.deleted, +.token.important { + color: hsl(355, 65%, 65%); +} + +.token.selector, +.token.string, +.token.char, +.token.builtin, +.token.inserted, +.token.regex, +.token.attr-value, +.token.attr-value > .token.punctuation { + color: hsl(95, 38%, 62%); +} + +.token.variable, +.token.operator, +.token.function { + color: hsl(207, 82%, 66%); +} + +.token.url { + color: hsl(187, 47%, 55%); +} + +/* HTML overrides */ +.token.attr-value > .token.punctuation.attr-equals, +.token.special-attr > .token.attr-value > .token.value.css { + color: hsl(220, 14%, 71%); +} + +/* CSS overrides */ +.language-css .token.selector { + color: hsl(355, 65%, 65%); +} + +.language-css .token.property { + color: hsl(220, 14%, 71%); +} + +.language-css .token.function, +.language-css .token.url > .token.function { + color: hsl(187, 47%, 55%); +} + +.language-css .token.url > .token.string.url { + color: hsl(95, 38%, 62%); +} + +.language-css .token.important, +.language-css .token.atrule .token.rule { + color: hsl(286, 60%, 67%); +} + +/* JS overrides */ +.language-javascript .token.operator { + color: hsl(286, 60%, 67%); +} + +.language-javascript + .token.template-string + > .token.interpolation + > .token.interpolation-punctuation.punctuation { + color: hsl(5, 48%, 51%); +} + +/* JSON overrides */ +.language-json .token.operator { + color: hsl(220, 14%, 71%); +} + +.language-json .token.null.keyword { + color: hsl(29, 54%, 61%); +} + +/* MD overrides */ +.language-markdown .token.url, +.language-markdown .token.url > .token.operator, +.language-markdown .token.url-reference.url > .token.string { + color: hsl(220, 14%, 71%); +} + +.language-markdown .token.url > .token.content { + color: hsl(207, 82%, 66%); +} + +.language-markdown .token.url > .token.url, +.language-markdown .token.url-reference.url { + color: hsl(187, 47%, 55%); +} + +.language-markdown .token.blockquote.punctuation, +.language-markdown .token.hr.punctuation { + color: hsl(220, 10%, 40%); + font-style: italic; +} + +.language-markdown .token.code-snippet { + color: hsl(95, 38%, 62%); +} + +.language-markdown .token.bold .token.content { + color: hsl(29, 54%, 61%); +} + +.language-markdown .token.italic .token.content { + color: hsl(286, 60%, 67%); +} + +.language-markdown .token.strike .token.content, +.language-markdown .token.strike .token.punctuation, +.language-markdown .token.list.punctuation, +.language-markdown .token.title.important > .token.punctuation { + color: hsl(355, 65%, 65%); +} + +/* General */ +.token.bold { + font-weight: bold; +} + +.token.comment, +.token.italic { + font-style: italic; +} + +.token.entity { + cursor: help; +} + +.token.namespace { + opacity: 0.8; +} + +/* Plugin overrides */ +/* Selectors should have higher specificity than those in the plugins' default stylesheets */ + +/* Show Invisibles plugin overrides */ +.token.token.tab:not(:empty):before, +.token.token.cr:before, +.token.token.lf:before, +.token.token.space:before { + color: hsla(220, 14%, 71%, 0.15); + text-shadow: none; +} + +/* Toolbar plugin overrides */ +/* Space out all buttons and move them away from the right edge of the code block */ +div.code-toolbar > .toolbar.toolbar > .toolbar-item { + margin-right: 0.4em; +} + +/* Styling the buttons */ +div.code-toolbar > .toolbar.toolbar > .toolbar-item > button, +div.code-toolbar > .toolbar.toolbar > .toolbar-item > a, +div.code-toolbar > .toolbar.toolbar > .toolbar-item > span { + background: hsl(220, 13%, 26%); + color: hsl(220, 9%, 55%); + padding: 0.1em 0.4em; + border-radius: 0.3em; +} + +div.code-toolbar > .toolbar.toolbar > .toolbar-item > button:hover, +div.code-toolbar > .toolbar.toolbar > .toolbar-item > button:focus, +div.code-toolbar > .toolbar.toolbar > .toolbar-item > a:hover, +div.code-toolbar > .toolbar.toolbar > .toolbar-item > a:focus, +div.code-toolbar > .toolbar.toolbar > .toolbar-item > span:hover, +div.code-toolbar > .toolbar.toolbar > .toolbar-item > span:focus { + background: hsl(220, 13%, 28%); + color: hsl(220, 14%, 71%); +} + +/* Line Highlight plugin overrides */ +/* The highlighted line itself */ +.line-highlight.line-highlight { + background: hsla(220, 100%, 80%, 0.04); +} + +/* Default line numbers in Line Highlight plugin */ +.line-highlight.line-highlight:before, +.line-highlight.line-highlight[data-end]:after { + background: hsl(220, 13%, 26%); + color: hsl(220, 14%, 71%); + padding: 0.1em 0.6em; + border-radius: 0.3em; + box-shadow: 0 2px 0 0 rgba(0, 0, 0, 0.2); /* same as Toolbar plugin default */ +} + +/* Hovering over a linkable line number (in the gutter area) */ +/* Requires Line Numbers plugin as well */ +pre[id].linkable-line-numbers.linkable-line-numbers span.line-numbers-rows > span:hover:before { + background-color: hsla(220, 100%, 80%, 0.04); +} + +/* Line Numbers and Command Line plugins overrides */ +/* Line separating gutter from coding area */ +.line-numbers.line-numbers .line-numbers-rows, +.command-line .command-line-prompt { + border-right-color: hsla(220, 14%, 71%, 0.15); +} + +/* Stuff in the gutter */ +.line-numbers .line-numbers-rows > span:before, +.command-line .command-line-prompt > span:before { + color: hsl(220, 14%, 45%); +} + +/* Match Braces plugin overrides */ +/* Note: Outline colour is inherited from the braces */ +.rainbow-braces .token.token.punctuation.brace-level-1, +.rainbow-braces .token.token.punctuation.brace-level-5, +.rainbow-braces .token.token.punctuation.brace-level-9 { + color: hsl(355, 65%, 65%); +} + +.rainbow-braces .token.token.punctuation.brace-level-2, +.rainbow-braces .token.token.punctuation.brace-level-6, +.rainbow-braces .token.token.punctuation.brace-level-10 { + color: hsl(95, 38%, 62%); +} + +.rainbow-braces .token.token.punctuation.brace-level-3, +.rainbow-braces .token.token.punctuation.brace-level-7, +.rainbow-braces .token.token.punctuation.brace-level-11 { + color: hsl(207, 82%, 66%); +} + +.rainbow-braces .token.token.punctuation.brace-level-4, +.rainbow-braces .token.token.punctuation.brace-level-8, +.rainbow-braces .token.token.punctuation.brace-level-12 { + color: hsl(286, 60%, 67%); +} + +/* Diff Highlight plugin overrides */ +/* Taken from https://github.com/atom/github/blob/master/styles/variables.less */ +pre.diff-highlight > code .token.token.deleted:not(.prefix), +pre > code.diff-highlight .token.token.deleted:not(.prefix) { + background-color: hsla(353, 100%, 66%, 0.15); +} + +pre.diff-highlight > code .token.token.deleted:not(.prefix)::-moz-selection, +pre.diff-highlight > code .token.token.deleted:not(.prefix) *::-moz-selection, +pre > code.diff-highlight .token.token.deleted:not(.prefix)::-moz-selection, +pre > code.diff-highlight .token.token.deleted:not(.prefix) *::-moz-selection { + background-color: hsla(353, 95%, 66%, 0.25); +} + +pre.diff-highlight > code .token.token.deleted:not(.prefix)::selection, +pre.diff-highlight > code .token.token.deleted:not(.prefix) *::selection, +pre > code.diff-highlight .token.token.deleted:not(.prefix)::selection, +pre > code.diff-highlight .token.token.deleted:not(.prefix) *::selection { + background-color: hsla(353, 95%, 66%, 0.25); +} + +pre.diff-highlight > code .token.token.inserted:not(.prefix), +pre > code.diff-highlight .token.token.inserted:not(.prefix) { + background-color: hsla(137, 100%, 55%, 0.15); +} + +pre.diff-highlight > code .token.token.inserted:not(.prefix)::-moz-selection, +pre.diff-highlight > code .token.token.inserted:not(.prefix) *::-moz-selection, +pre > code.diff-highlight .token.token.inserted:not(.prefix)::-moz-selection, +pre > code.diff-highlight .token.token.inserted:not(.prefix) *::-moz-selection { + background-color: hsla(135, 73%, 55%, 0.25); +} + +pre.diff-highlight > code .token.token.inserted:not(.prefix)::selection, +pre.diff-highlight > code .token.token.inserted:not(.prefix) *::selection, +pre > code.diff-highlight .token.token.inserted:not(.prefix)::selection, +pre > code.diff-highlight .token.token.inserted:not(.prefix) *::selection { + background-color: hsla(135, 73%, 55%, 0.25); +} + +/* Previewers plugin overrides */ +/* Based on https://github.com/atom-community/atom-ide-datatip/blob/master/styles/atom-ide-datatips.less and https://github.com/atom/atom/blob/master/packages/one-dark-ui */ +/* Border around popup */ +.prism-previewer.prism-previewer:before, +.prism-previewer-gradient.prism-previewer-gradient div { + border-color: hsl(224, 13%, 17%); +} + +/* Angle and time should remain as circles and are hence not included */ +.prism-previewer-color.prism-previewer-color:before, +.prism-previewer-gradient.prism-previewer-gradient div, +.prism-previewer-easing.prism-previewer-easing:before { + border-radius: 0.3em; +} + +/* Triangles pointing to the code */ +.prism-previewer.prism-previewer:after { + border-top-color: hsl(224, 13%, 17%); +} + +.prism-previewer-flipped.prism-previewer-flipped.after { + border-bottom-color: hsl(224, 13%, 17%); +} + +/* Background colour within the popup */ +.prism-previewer-angle.prism-previewer-angle:before, +.prism-previewer-time.prism-previewer-time:before, +.prism-previewer-easing.prism-previewer-easing { + background: hsl(219, 13%, 22%); +} + +/* For angle, this is the positive area (eg. 90deg will display one quadrant in this colour) */ +/* For time, this is the alternate colour */ +.prism-previewer-angle.prism-previewer-angle circle, +.prism-previewer-time.prism-previewer-time circle { + stroke: hsl(220, 14%, 71%); + stroke-opacity: 1; +} + +/* Stroke colours of the handle, direction point, and vector itself */ +.prism-previewer-easing.prism-previewer-easing circle, +.prism-previewer-easing.prism-previewer-easing path, +.prism-previewer-easing.prism-previewer-easing line { + stroke: hsl(220, 14%, 71%); +} + +/* Fill colour of the handle */ +.prism-previewer-easing.prism-previewer-easing circle { + fill: transparent; +} diff --git a/yarn.lock b/yarn.lock index a074c3a..b405874 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2020,6 +2020,11 @@ remark-emoji@^3.0.2: node-emoji "^1.11.0" unist-util-visit "^4.1.0" +remark-footnotes@2.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/remark-footnotes/-/remark-footnotes-2.0.0.tgz#9001c4c2ffebba55695d2dd80ffb8b82f7e6303f" + integrity sha512-3Clt8ZMH75Ayjp9q4CorNeyjwIxHFcTkaektplKGl2A1jNGEUey8cKL0ZC5vJwfcD5GFGsNLImLG/NGzWIzoMQ== + remark-gfm@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/remark-gfm/-/remark-gfm-3.0.1.tgz#0b180f095e3036545e9dddac0e8df3fa5cfee54f"