跳转至

博客

每周分享第 38 期

  1. 针对部分 HTTP/2 实现的新漏洞 https://github.com/Netflix/security-bulletins/blob/master/advisories/third-party/2019-002.md
  2. 只读 tmux 加魔改 https://brianmckenna.org/blog/guest_tmux
  3. Rust 编译期断言 https://github.com/nvzqz/static-assertions-rs
  4. Rust 运行时解压版的 include_bytes https://github.com/SOF3/include-flate
  5. 把 Rust 标准库进行 async 化的尝试 https://async.rs/blog/announcing-async-std/#
  6. git 添加 switch/restore 命令 https://github.blog/2019-08-16-highlights-from-git-2-23/
  7. Flash Player in Rust https://github.com/ruffle-rs/ruffle
  8. Matplotlib Cheatsheet https://github.com/rougier/matplotlib-cheatsheet
  9. macOS Catalina 10.15 beta 6 发布
  10. Flash Decompiler https://github.com/jindrapetrik/jpexs-decompiler
  11. Yubikey 发布 5Ci https://readhacker.news/s/489yu
  12. IBM 开放 Power 指令集 https://readhacker.news/s/48aiH
  13. iOS 13 beta 8 发布
  14. GitHub 支持 WebAuthn https://readhacker.news/s/48dXM
  15. 编译器优化带来的安全漏洞 https://readhacker.news/s/48dke
  16. obscure C features https://multun.net/obscure-c-features.html

每周分享第 37 期

  1. Rust netlink 库 https://github.com/jbaublitz/neli
  2. Rust 处理 signal 进行配置的 reload https://vorner.github.io/2019/08/11/runtime-configuration-reloading.html
  3. macOS 添加了 VirtIO 驱动支持 https://passthroughpo.st/mac-os-adds-early-support-for-virtio-qemu/
  4. 一个 GNU readline 替代品 https://github.com/AmokHuginnsson/replxx
  5. Rust 1.37.0 发布 https://blog.rust-lang.org/2019/08/15/Rust-1.37.0.html
  6. iOS 13 DB7 (17A5565b) 发布

macOS 下读取并解析 EDID

之前听说了 EDID 的存在,但是一直没有细究里面的格式和内容。今天了解了一下,发现其实非常简单,下面是方法:

首先获取所有显示器输出的 EDID:

ioreg -lw0 | grep IODisplayEDID

输出里会出现 "IODisplayEDID" = <00ffxxxxxxxxxxxxx> 的内容,尖括号内的就是 EDID 的内容。接着,我们采用 edid-decode 进行解析:

git clone git://linuxtv.org/edid-decode.git
cd edid-decode
make
./edid-decode
<Paste EDID here>

就可以看到很详细的 EDID 数据解析了。

ref: https://gist.github.com/OneSadCookie/641549 https://www.avsforum.com/forum/115-htpc-mac-chat/1466910-ability-dump-display-s-edid-mac.html

在 Linux 下捕获 Framebuffer

最近需要在 linux 下抓取 Framebuffer 的内容,在网上找到了两种方法,在我这里只有第二、第三种可以成功,没有细究具体原因,可能与我的 Framebuffer 配置有关。方法如下:

  1. fbgrab :命令就是 fbgrab image.png,直接得到 png 文件,格式是对的,但是用软件打开就是一片空白。用 ImageMagick 转换为 jpg 可以看到一些内容,但是和实际有些不一样。
  2. fbdump :命令就是 fbdump > image.ppm,得到裸的 ppm 文件,图像是正确的,也可以转换为别的格式正常打开。
  3. cat+脚本处理:直接 cat /dev/fb0 > image.rgb,然后用下面的脚本转换为 png。由于 Framebuffer 格式为 RGB,本来 A 所在的 channel 都为 0,所以用一些软件直接打开都是空白,只好写了脚本直接跳过 Alpha Channel。

Framebuffer 配置( fbset 输出):

mode "640x480-0"
        # D: 0.000 MHz, H: 0.000 kHz, V: 0.000 Hz
        geometry 640 480 1024 480 32
        timings 0 0 0 0 0 0 0
        accel false
        rgba 8/16,8/8,8/0,0/0
endmode

转换脚本(参考 [Tips] 擷取 framebuffer 畫面):

#!/usr/bin/perl -w

$w = shift || 240;
$h = shift || 320;
$pixels = $w * $h;

open OUT, "|pnmtopng" or die "Can't pipe pnmtopng: $!\n";

printf OUT "P6%d %d\n255\n", $w, $h;

while ((read STDIN, $raw, 4) and $pixels--) {
   $short = unpack('I', $raw);
   print OUT pack("C3",
      ($short & 0xff0000) >> 16,
      ($short & 0xff00) >> 8,
      ($short & 0xff));
}

close OUT;

用法: cat image.rgb | perl script.pl 1024 480 > console.png

每周分享第 36 期

  1. QuickJS + libuv https://github.com/saghul/qjsuv
  2. Rust 实现的 Ruby https://github.com/artichoke/artichoke
  3. 类似 JSON 的数据格式 https://cbor.io/
  4. rls 二代目 https://github.com/rust-analyzer/rust-analyzer
  5. 给 MacBook 添加触屏支持 https://github.com/bijection/sistine
  6. 用于 MBP with T2 的 Linux patch https://github.com/aunali1/linux-mbp-arch
  7. 在 tmux 中使用 Touch ID 认证 sudo https://blog.birkhoff.me/make-sudo-authenticate-with-touch-id-in-a-tmux/
  8. iOS 13 beta 6 发布
  9. Linux Journal 结束了它的使命
  10. ssh 8.0 Add support for ECDSA keys in PKCS#11 tokens

用 PulseView 配合 DSLogic 调试 SPI Flash

最近需要用到逻辑分析仪来调试 SPI Flash,设备是 DreamSourceLab 的 DSLogic,最开始用的是官方的 DSView,确实能够抓到 SPI 的信号,也可以解析出一些 SPI Flash 的数据,但是很多是不完整的。

后来把源码下载下来,发现是基于 sigrok 和 PulseView 做的一个魔改版,然后 sigrok 官网上最新的版本已经支持了 DSLogic,于是就用 PulseView 替代 DSView。一开始遇到的问题是没有 firmware,一番搜索找到了解决方案,按照脚本下载好文件即可。

进到 PulseView 以后,把 SPI 的四路信号接上,然后抓了一段信号,解析:

可以看到它正确地解析出来了 Fast Read 命令。由于 DSView 它 fork 自一个比较老的版本,所以它并不能正确解析出来。

P.S. Linux 下它界面显示比 macOS 下好看一些,估计是没有适配好。

每周分享第 35 期

  1. Apple Touch Bar 的 Windows 第三方支持 https://github.com/imbushuo/DFRDisplayKm
  2. WSL2 新的进展 http://www.phoronix.com/scan.php?page=news_item&px=Windows-WSL2-Localhost-Plus
  3. Lightning 转接头里面居然跑 iBoot 和 Darwin https://readhacker.news/s/46Zde
  4. iOS 13 beta 5 发布
  5. ES2019 前瞻 https://blog.tildeloop.com/posts/javascript-what%E2%80%99s-new-in-es2019
  6. Rust 可持久化数据结构 https://github.com/orium/rpds
  7. Rust 不可变数据结构 https://github.com/bodil/im-rs
  8. macOS Catalina 10.15 beta 5 发布
  9. Algebraic Effect https://overreacted.io/algebraic-effects-for-the-rest-of-us/
  10. Donald Knuth 对于 Sensitivity Proof 证明的简化 https://readhacker.news/s/47fsA 真是老当益壮
  11. TLS1.3 标准的简化版 https://readhacker.news/s/47eG9
  12. iTerm 3.3 发布 https://iterm2.com/downloads/stable/iTerm2-3_3_0.changelog

每周分享第 34 期

  1. macOS Mojave 10.14.6 iOS 12.4 正式版更新发布,还有老版本的更新 https://www.macrumors.com/2019/07/22/apple-releases-gps-bug-fix-older-iphones-ipads/
  2. CLion 2019.2 添加了 GDB Server 的调试支持,可以用 OpenOCD。

每周分享第 33 期

  1. 一个讲 Rust 比较硬核的博客 http://system.joekain.com/
  2. 利用 fzf 实现 shell 的 REPL https://github.com/pawelduda/fzf-live-repl
  3. 类似 Vue 的前端 Go 框架 https://www.vugu.org/doc/start
  4. iOS 13 beta 4 发布 14A5534f
  5. 针对 T2 NVMe 的 patch http://www.phoronix.com/scan.php?page=news_item&px=NVMe-Patches-LKML-Apple-Mac
  6. 一个前端非对称加密的问卷网站 https://blog.fugoes.xyz/crypto-q/

前端解析上传的 CSV

之前做过一个在前端解析上传的 CSV 的功能,但是只能支持部分的 encoding,遇到 gbk 就傻眼了。一番研究以后,找到了比较科学的方案:

import * as Chardet from 'chardet';
import * as Iconv from 'iconv-lite';

const reader = new FileReader();
reader.onload = (e) => {
  const data = e.target.result;
  const view = Buffer.from(data);
  // detect encoding and convert
  const encoding = Chardet.detect(view);
  const result = Iconv.decode(view, encoding);
  const csvData = Papa.parse(result).data;
  // do anything with it
};

reader.readAsArrayBuffer(blob_here);

依赖了两个库:chardeticonv-lite ,测试了一下,解析 UTF-8 GBK UTF-16BE 都没问题。

P.S. 在生成 csv 的时候,也会出现 Excel 打开后乱码的问题,一开始我以为需要转 UTF-16 然后再添加 BOM Mark,后来发现只要在最前面加上 0xEF 0xBB 0xFB(UTF-8 编码下的 BOM Mark)即可。

每周分享第 32 期

  1. Rpi4 的 Type-C 设计有问题 https://readhacker.news/s/45WYc
  2. Debian buster released
  3. USB Type-C Serial adapter with WCH/FTDI https://github.com/z4yx/USB-C-Serial
  4. Linux 5.2 Kernel released http://www.phoronix.com/scan.php?page=news_item&px=Linux-5.2-Released
  5. iOS/iPadOS PB2 发布,与 DB3 差了一个小版本号
  6. Pacman in 512 bytes of x86 boot sector machine code https://readhacker.news/s/466Zm
  7. clang 的 use after move checker 使用 https://awesomekling.github.io/Catching-use-after-move-bugs-with-Clang-consumed-annotations/

每周分享第 31 期

  1. 一个 Docker 的 TUI https://github.com/jesseduffield/lazydocker
  2. 在线 Git cheatsheet http://ndpsoftware.com/git-cheatsheet.html
  3. 带历史合并两个 Git 仓库 https://stackoverflow.com/a/10548919
  4. iOS 13 Dev Beta 3 https://mp.weixin.qq.com/s/6cxLXOYgeP6QkDpa9kdoug
  5. iOS 13 FaceTime Attention Correction https://readhacker.news/s/45QX2

每周分享第 30 期

  1. 一个可参考的防止 side channel attack 的方法 https://www.undeadly.org/cgi?action=article;sid=20190621081455

  2. 物理上镜像百兆的方法 实测可用 https://greatscottgadgets.com/throwingstar/

  3. 微软员工写的 malloc https://github.com/microsoft/mimalloc

  4. 超标量乱序执行的 x86 软核 https://tspace.library.utoronto.ca/bitstream/1807/80713/1/Wong_Henry_T_201711_PhD_thesis.pdf

  5. Rust 的 wireshark 替代 https://github.com/kpcyrd/sniffglue

  6. Rpi 4 发布 https://readhacker.news/s/45nK9

  7. iOS/macOS Catalina PB1 发布(= DB2)

  8. dbg! 移植到了 C++ https://github.com/sharkdp/dbg-macro

  9. 类似于 Elm 的 Rust 前端框架 https://github.com/David-OConnor/seed

  10. 访问 VMware 虚拟机串口的方法 https://thewayeye.net/2009/december/4/connecting-virtual-machines-serial-console-os-x-and-vmware-fusion/

每周分享第 29 期

  1. ZFS on Linux 发布 0.8.1 https://github.com/zfsonlinux/zfs/releases/tag/zfs-0.8.1
  2. slim: Dockerfile to VM image https://github.com/ottomatica/slim
  3. Rust 重写的 du 替代物 确实很快 https://github.com/Byron/dua-cli
  4. iOS 13/macOS Catalina beta 2 出了 并且可以 OTA 相关信息 https://9to5mac.com/2019/06/17/ios-13-beta-2-features/ https://developer.apple.com/documentation/macos_release_notes/macos_catalina_10_15_beta_2_release_notes https://mp.weixin.qq.com/s/Ae1SIcK9ho4Mh0g_UsbAyA
  5. Steam 已经解决了 Catalina 上 32 位程序不能运行的问题 https://www.reddit.com/r/MacOS/comments/c17lh8/steam_and_macos_catalina
  6. 在一些老的 Mac 上 Sidecar 是默认关闭的,但是可以开启 https://github.com/pookjw/SidecarPatcher/blob/master/README.md 虽然效果不会很好

IP 前缀转换上意外遇到的 Undefined Behavior

最近发现了两个很神奇的 Undefined Behavior,出现在 Prefix Len 和 Netmask 的转换的问题下。一个简单思路可能是:

#define PREFIX_BIN2DEC(bin) (32 - __builtin_ctz((bin)))
#define PREFIX_DEC2BIN(hex) (((~0) >> (32 - (hex))) << (32 - (hex))

乍一看,似乎没有什么问题。但是,在一些平台下,可能会出现这样的结果:

PREFIX_BIN2DEC(0x00000000) = 33
PREFIX_DEC2BIN(0) = 0xFFFFFFFF

而且只能在一些平台上不确定地复现,最后发现其实是 Undefined Behavior,在 C 的标准中:

In any case, the behavior is undefined if rhs is negative or is greater or equal the number of bits in the promoted lhs.

意味着, 0xFFFFFFFF >> 32 是一个 UB,所以出现了上面的问题。

另外,__builtin_ctz 有这样的说明:

Returns the number of trailing 0-bits in x, starting at the least significant bit position. If x is 0, the result is undefined.

意味着,__builtin_ctz(0) 也是一个 UB,所以得到了错误的结果。

解决方案也很简单,下面提供一个参考的解决方法:

#define PREFIX_BIN2DEC(bin) ((bin) ? (32 - __builtin_ctz((bin))) : 0)
#define PREFIX_DEC2BIN(hex) (((uint64_t)0xFFFFFFFF << (32 - (hex))) & 0xFFFFFFFF)

Quagga 的实现:

/* Convert masklen into IP address's netmask (network byte order). */
void
masklen2ip (const int masklen, struct in_addr *netmask)
{
  assert (masklen >= 0 && masklen <= IPV4_MAX_BITLEN);

  /* left shift is only defined for less than the size of the type.
   * we unconditionally use long long in case the target platform
   * has defined behaviour for << 32 (or has a 64-bit left shift) */

  if (sizeof(unsigned long long) > 4)
    netmask->s_addr = htonl(0xffffffffULL << (32 - masklen));
  else
    netmask->s_addr = htonl(masklen ? 0xffffffffU << (32 - masklen) : 0);
}

/* Convert IP address's netmask into integer. We assume netmask is
   sequential one. Argument netmask should be network byte order. */
u_char
ip_masklen (struct in_addr netmask)
{
  uint32_t tmp = ~ntohl(netmask.s_addr);
  if (tmp)
    /* clz: count leading zeroes. sadly, the behaviour of this builtin
     * is undefined for a 0 argument, even though most CPUs give 32 */
    return __builtin_clz(tmp);
  else
    return 32;
}

BIRD 的解决方法:

/**
 * u32_mkmask - create a bit mask
 * @n: number of bits
 *
 * u32_mkmask() returns an unsigned 32-bit integer which binary
 * representation consists of @n ones followed by zeroes.
 */
u32
u32_mkmask(uint n)
{
  return n ? ~((1 << (32 - n)) - 1) : 0;
}

/**
 * u32_masklen - calculate length of a bit mask
 * @x: bit mask
 *
 * This function checks whether the given integer @x represents
 * a valid bit mask (binary representation contains first ones, then
 * zeroes) and returns the number of ones or 255 if the mask is invalid.
 */
uint
u32_masklen(u32 x)
{
  int l = 0;
  u32 n = ~x;

  if (n & (n+1)) return 255;
  if (x & 0x0000ffff) { x &= 0x0000ffff; l += 16; }
  if (x & 0x00ff00ff) { x &= 0x00ff00ff; l += 8; }
  if (x & 0x0f0f0f0f) { x &= 0x0f0f0f0f; l += 4; }
  if (x & 0x33333333) { x &= 0x33333333; l += 2; }
  if (x & 0x55555555) l++;
  if (x & 0xaaaaaaaa) l++;
  return l;
}

每周分享第 28 期

  1. Rust Sec https://github.com/RustSec/advisory-db
  2. opendrop 开源的 AirDrop 实现 https://github.com/seemoo-lab/opendrop
  3. 代码内嵌图片 https://javl.github.io/image2cpp/
  4. RAMBleed 攻击 https://readhacker.news/s/44MHD
  5. WSL2 可以体验了 https://devblogs.microsoft.com/commandline/wsl-2-is-now-available-in-windows-insiders/
  6. Rust 2019 生态报告 https://www.jetbrains.com/lp/devecosystem-2019/rust/

每周分享第 27 期

高考加油!

  1. Fallout 漏洞 https://arxiv.org/abs/1905.12701
  2. PageRank 专利到期 https://patents.google.com/patent/US6285999B1/en
  3. 终端电量可视化 https://github.com/svartalf/rust-battop
  4. 查找 DB 的 DB https://dbdb.io
  5. 在 Rust 里写 GPU 程序 https://github.com/calebwin/emu
  6. WWDC 2019 挺不错的
  7. Alfred 4 发布 https://www.alfredapp.com/blog/announcements/alfred-4-is-here/
  8. Mac Pro AR https://www.apple.com/105/media/us/mac-pro/2019/36178e80-30fd-441c-9a5b-349c6365bb36/quick-look/case-on.usdz
  9. VSCode 稳定版也可以 Remote 了 https://code.visualstudio.com/docs/remote/ssh
  10. 2019 高考语文作文 https://mp.weixin.qq.com/s/2NwkbbMlAUJpOKKuln1T4g

在 FPGA 上实现路由器(3)

前言

又半个月过去了,在写了上篇系列博文之后也是做了很多新的更改。上次做的主要是关于性能方面的提升,怎么提高频率,从而达到比较大的流量,而这段时间做的则是功能,做实现 RIP 协议和转发表的动态更新。

软件部分

软件部分目前是用 C 代码写的,用 Xilinx SDK 提供的各个 AXI 外设的驱动和 PS 自己的驱动,实现了所需要的,RIP 协议的处理,转发表的更新和统计信息的读取。

实际上做的时候比较粗暴,主要是通过三种 AXI 外设与硬件部分进行交互:AXI Stream FIFO,AXI GPIO 和 AXI BRAM Controller。其中 AXI Stream FIFO 是用来接收和发送需要 CPU 处理的以太网帧的,AXI GPIO 则是用来读取统计的信息,AXI BRAM Controller 是用来读写转发表的。最后在顶层设计中把这些外设连接起来。

硬件部分

硬件部分还是继续之前的部分往下写,添加了统计信息,直接暴露出去,让 CPU 走 AXI GPIO 读,因为不需要很高的精确度;转发表本身,一开始想的是自己写一些接口转换,后来发现,直接用 True Dual Port RAM 然后把一个 port 暴露给 AXI BRAM Controller 即可,免去了各种麻烦,PS 可以直接进行修改,不需要额外的工作。

最终效果

为了测试这套东西是否正常工作,就开了两个 Arch Linux 的虚拟机,分别 Bridge 到两个千兆的 USB 网卡上,都连到 FPGA 上。然后在两边都配上了 BIRD,配置 RIP 和一些路由,确实能更新硬件的转发表,并两边的 RIP 可以学习到对方的路由。

每周分享第 26 期

  1. Grafana 6.2 发布 https://grafana.com/blog/2019/05/22/grafana-v6.2-released/
  2. Program Synthesis Talk by Paul Zhu https://paulz.me/talk/program-synthesis/
  3. VSCode 摸鱼插件 https://github.com/cteams/Thief-Book
  4. 编译期 C++ 计算器 https://www.zhihu.com/question/28582706/answer/691444859
  5. 一个在线的 tomasulo 算法实现 https://tomasulo.harrychen.xyz/
  6. Safari Technology Preview 83 发布,含 WebAuthN 支持 https://webkit.org/blog/8967/release-notes-for-safari-technology-preview-83/
  7. Markdown -> 微信 https://github.com/lyricat/wechat-format
  8. Rust 的 Code Coverage 库 https://github.com/xd009642/tarpaulin

IP 和 UDP Checksum 的增量更新问题

之前在写 IP Checksum 的增量更新,就是当 TTL -= 1 的时候,Checksum 应该增加 0x0100,但是这样会有问题,在于,如果按照原来的 IP Checksum 计算方法,是不会出现 0xFFFF 的(求和,进位,然后取反写入),这种加法就有可能出现 0xFFFF。于是翻阅了相关的 RFC:

首先是 RFC 1141 相关部分:

unsigned long sum;
ipptr->ttl--;                  /* decrement ttl */
sum = ipptr->Checksum + 0x100;  /* increment checksum high byte*/
ipptr->Checksum = (sum + (sum>>16)) /* add carry */

这也是比较直接能想到的一种方法,但是会出现刚才提到的问题。于是 RFC 1624 纠正了这个问题:

  Although this equation appears to work, there are boundary conditions
   under which it produces a result which differs from the one obtained
   by checksum computation from scratch.  This is due to the way zero is
   handled in one's complement arithmetic.

   In one's complement, there are two representations of zero: the all
   zero and the all one bit values, often referred to as +0 and -0.
   One's complement addition of non-zero inputs can produce -0 as a
   result, but never +0.  Since there is guaranteed to be at least one



Rijsinghani                                                     [Page 2]

RFC 1624             Incremental Internet Checksum              May 1994


   non-zero field in the IP header, and the checksum field in the
   protocol header is the complement of the sum, the checksum field can
   never contain ~(+0), which is -0 (0xFFFF).  It can, however, contain
   ~(-0), which is +0 (0x0000).

   RFC 1141 yields an updated header checksum of -0 when it should be
   +0.  This is because it assumed that one's complement has a
   distributive property, which does not hold when the result is 0 (see
   derivation of [Eqn. 2]).

   The problem is avoided by not assuming this property.  The correct
   equation is given below:

          HC' = ~(C + (-m) + m')    --    [Eqn. 3]
              = ~(~HC + ~m + m')

只要把代码简单修改一下就可以了,或者遇到 0xFFFF 时设为 0,这时候就解决了这个问题。

但是,仔细研究了一下发现,UDP Checksum 又是这么定义的(RFC 768):

If the computed  checksum  is zero,  it is transmitted  as all ones (the
equivalent  in one's complement  arithmetic).   An all zero  transmitted
checksum  value means that the transmitter  generated  no checksum  (for
debugging or for higher level protocols that don't care).

刚好和 IP Checksum 相反,这就很有意思了。

用 htpdate 替代 ntpdate 实现时间同步

最近用 ntpdate 的时候遇到了一些麻烦,时间同步总是遇到各种问题。后来搜了搜,发现了一个解决方案:htpdate,它通过 HTTP 头里的 Date 字段获取时间,虽然没有 ntp 那么精确,但是大多时候都够用。

用法见 htpdate(8)

每周分享第 25 期

  1. 关掉各种 Intel BUG 的 mitigation https://t.me/one_real_world/1517
  2. GCC 10 支持用 MMX 模拟 SSE http://www.phoronix.com/scan.php?page=news_item&px=GCC-10-Emulating-MMX-With-SSE
  3. Minecraft Earth 发布 https://www.minecraft.net/en-us/article/new-game--minecraft-earth#
  4. Python 官方 format 工具 https://github.com/python/black
  5. JS Binary AST Proposal https://github.com/tc39/proposal-binary-ast
  6. 用 Rust 实现的 ld https://github.com/aep/elfkit
  7. Verilog -> Minecraft https://github.com/itsFrank/MinecraftHDL
  8. Rust 实现的 光栅化输出 https://github.com/ecumene/rust-sloth/
  9. Nokia 的 Rust 内存 profiler https://github.com/nokia/memory-profiler
  10. Linux 5.2 更新的 Logitech Wireless Device 驱动 正好能用上 http://www.phoronix.com/scan.php?page=news_item&px=Better-Logitech-Linux-5.2

Nginx 反代到 HTTPS 上游

这次遇到一个需求,要反代到不在内网的地址,为了保证安全,还是得上 HTTPS,所以尝试了一下怎么给 upstream 配置自签名 HTTPS 证书的验证。

upstream subpath {
    server 4.3.2.1:4321;
}

server {
    listen 443 ssl;
    server_name test.example.com;

    location /abc {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_ssl_trusted_certificate /path/to/self_signed_cert.crt;
        proxy_ssl_name 1.2.3.4; // to override server name checking
        proxy_ssl_verify on;
        proxy_ssl_depth 2;
        proxy_ssl_reuse on;
        proxy_pass https://subpath;
    }
}

可以用 openssl 获得自签名的 cert :

echo | openssl s_client -showcerts -connect 4.3.2.1:4321 2>/dev/null | \
                              openssl x509 -text > /path/to/self_signed_cert.crt

ref: https://stackoverflow.com/questions/7885785/using-openssl-to-get-the-certificate-from-a-server

如果上游的 SSL/TLS 比较老,可能还需要添加一个选项来兼容:

proxy_ssl_conf_command Options UnsafeLegacyRenegotiation;

ref: https://stackoverflow.com/questions/77990465/nginx-fail-forwarding-with-ssl-error0a000152ssl-routinesunsafe-legacy-reneg

每周分享第 24 期

  1. 在线波形绘制 https://wavedrom.com/editor.html
  2. Python 波形绘制 https://github.com/wallento/wavedrompy
  3. GDB 8.3 发布 http://www.phoronix.com/scan.php?page=news_item&px=GDB-8.3-Debugger-Released
  4. 命令行自动搜索 StackOverflow https://github.com/WindSoilder/hors
  5. 从 C 到 Rust 的翻译 https://github.com/immunant/c2rust
  6. SHA-1 碰撞攻击新进展 https://www.zdnet.com/article/sha-1-collision-attacks-are-now-actually-practical-and-a-looming-danger/
  7. macOS 配置 AD 管理员组 https://derflounder.wordpress.com/2011/02/17/adding-groups-from-your-directory-service-to-your-macs-admin-group/
  8. ssh 后自动安装并打开 code-server 同步配置 https://github.com/cdr/sshcode
  9. HTTP Sunset 头 https://tools.ietf.org/html/rfc8594

在 FPGA 上实现路由器(2)

前言

月初的时候,有了一个完整可用的路由器(上一篇系列博文),但当时测了一下速度,只有几十 Mb/s,只要往上提就会失效,得 reset 才能继续。当时也先没管性能的事情,先把和 OS 交互的部分做了。现在又回头来做性能调优。

之前,逻辑部分的主频只有 10 MHz,这自然不行,不提高肯定做不到千兆。于是试着把主频拉高,FIFO 加大,然后遇到了很多问题,慢慢修复了,学到了很多新知识,目前也接近千兆的水平了吧,贴图:

TCP 测速:

UDP 测速:

测试环境是 macOS 虚拟机外打虚拟机内,走网桥把虚拟机和一个 USB 网卡接起来,然后从另一个 USB 网卡打到路由器。

尝试 700Mb/s

接下来讲讲,在这个过程中遇到了什么问题,怎么解决的。第一个是速度过快就会挂,这肯定是丢包逻辑没写对,后来在仿真里开够了时间,于是就找到了一个 BUG,其实就是一行的修复。接着就是提高主频,但大家也知道,CPU 不能随便超频,由于各种延迟的原因,比如 Setup 时间,如果超了一个时钟周期的时间,本来应该下个周期就得到新数据的,结果到了下下周期才有,那有的状态可能就乱了,我目前遇到的也主要就是这个问题。

于是就对着 Timing 里汇报的各种问题修啊修,发现了很多以前没有注意到的问题,它们不影响功能,但是会让逻辑变慢。第一个问题是 High Fanout,以上就是说一个输出接到了很多输入,这看起来没啥问题,但数设课上也讲过,每个门的输入输出电流是有限制的,例如按书上的数据,一个门输出只能带十个门,更多只能级联一层。级联的话,延迟自然就高了。后来发现,这里的原因是,开了一个大的数组,但是没有变成 RAM,综合出了几千个逻辑单元,自然是出问题。解决方法很简单,用 xpm_memory_tpdram 即可。这样一搞,主频就能上 200MHz 了。

这个时候测了一下,发现 UDP 能打到 700Mb/s 了,TCP 由于丢包率比较高,只有 400Mb/s,距离预期还有一段距离。于是继续进行优化。

向 900Mb/s 进发

要继续提速,自然要提高主频。下一个主频目标就是 250MHz。随着提高主频,时序的要求也会更高,自然也出现了新的问题。

这次的问题主要在于,一个路径上逻辑门数过多,多的有 7 到 10 个,每一步零点几到一点几纳秒,叠起来 4 纳秒哪里够用。于是把一些不需要依赖条件的逻辑挪到条件外面,这样就减少了一些路径的依赖。

解决了这个以后,现在的 WNS(Worst Negative Slack)只剩下 0.6 ns 了。这时候的问题一部分还是来自于逻辑门过多,但这个时候就没这么简单了,只能继续细化流水线,打一拍,这样才能把延迟降下来。

虽然 Timing 没有完全解决,但还是写进了 FPGA 中。幸好工作一切正常,就得到了上面那个图片的结果,接近千兆的速度了。

后续优化途径

后续优化途径的话,一方面是继续对逻辑进行细化和拆分,另一方面是对架构进行优化。当初设计的时候,可能没有考虑地那么周全,例如现在发现,其实 ARP Cache 可以放到每个网口一份,这样会降低花在仲裁上的时间。另外,路由表其实也可以分多份存,只要改的时候同一改就可以了。这样应该会更快。