作者归档:mzh

OpenWRT 防火墙开启IPv6 端口转发的方法

前言

OpenWRT当启用IPv6时,默认情况下流量会经过主路由防火墙。在外部网络环境中,若想访问家庭局域网内的服务(如SSH、Proxy、NAS等),默认请求将被防火墙拦截,因此需在主路由防火墙中添加允许规则。
这里并不推荐禁用IPv6防火墙:虽然IPv6地址和端口扫描难度较大,但仍存在被扫描风险。所有局域网服务可能暴露于外网,即使未受攻击,家庭宽带提供公网服务也可能被ISP警告。

LUCI网页界面配置

打开OpenWRT路由管理页面,进入 网络 - 防火墙 - 流量规则。

点击 添加 创建新规则。流量规则区的规则优先级高于默认规则,无需担心与默认规则冲突,但需注意同页其他规则的优先级。可通过拖拽调整规则顺序。

规则配置示例:

  • 名称:清晰标识规则用途(例如如 NAS IPv6)。
  • 协议:按需选择协议,不确定时可同时选TCP和UDP。
  • 源区域:选择 WAN(外网流量入口)。
  • 源地址/源端口:留空。
  • 目标区域:选择 LAN(内网目标区域)。
  • 目标地址: 链路本地IPv6地址(通常以 fe80:: 开头)。

移除链路本地前缀(如 fe80::20c:29ff:fed7:fbf 改为 ::20c:29ff:fed7:fbf)。

追加掩码 /::ffff:ffff:ffff:ffff,最终填入 ::20c:29ff:fed7:fbf/::ffff:ffff:ffff:ffff。此配置确保客户端即使因ISP分配的前缀变化仍能被匹配。

目标端口:指定允许的端口(如 80-443)。留空将放行所有端口,存在重大安全风险,不建议。

动作:选择 接受(Accept)。

高级设置:地址族改为 IPv6,其他保持默认。

保存后,可测试外网访问内网服务。若在 状态 - 防火墙 的 forward_wan 链中看到规则及计数器,则规则已生效。

凑了台DL20Gen9

最近攒了台DL20Gen9垃圾服务器,准备做成All-in-one(路由、NAS、监控)。
为了节省磁盘的电,就买了2块硬盘的版本。

DL20gen9

配置清单:

  • 某宝淘的准系统 (¥700)
  • Intel(R) Xeon(R) CPU E3-1270 v5 @ 3.60GHz (¥113)
  • 4 x 16GB 2133 ECC Unbuffered 三星内存 (¥600)
  • 2 x 12 TB 氦气盘 (¥1180)
  • 256G 长城nvme (¥113)
  • HP Ethernet 10Gb 2-port 560SFP+ Adapter (¥99)

总记:¥2777

  • DL20gen9 支持最大64G 2133/2400 ECC内存(Unbuffered,某宝上一般叫纯ECC,别买错了)。
  • 想用最大的内存,2133只能配v5的CPU,2400只能配v6,如果混着了,就只能识别一半出来。
  • 如果你买到了坏的CPU,可能会出现DIMM cann't train的错误提示(我就因此换了所有硬件,最后只能是归到CPU上了)
  • 各种固件需要自己更新,要不然一些v5的CPU是无法识别的。

方便链接

iLo4 更新,主要是为了HTML5 的remote console
https://pingtool.org/latest-hp-ilo-firmwares/

System ROM(BIOS)
https://www.chiphell.com/forum.php?mod=viewthread&tid=2643119&extra=page%3D1&ordertype=2&mobile=no

HP这iLo还要许可证,坑爹到家了,贴一个在这了。
iLO 4 高级许可证密钥:
35DPH-SVSXJ-HGBJN-C7N5R-2SS4W
35SCR-RYLML-CBK7N-TD3B9-GGBW2

FreeBSD ports初体验

在开源操作系统的世界里,FreeBSD凭借其稳定性和强大的功能,赢得了不少技术爱好者的青睐。
而FreeBSD中的Ports系统,更是为这款操作系统增添了不少色彩。今天我就分享下我的初次ports体验。

Ports的背景和优势

Ports是FreeBSD中的一个软件包管理系统,它类似于其他操作系统中的包管理器(如Linux中的apt、yum等)。apt,yum更类似FreeBSD中的pkg程序,分发的是二进制包,而Ports系统是为用户提供了一个集中的地方来存储、分发和更新各种开源软件源码编译方式

Ports系统具有以下几个显著优势:

  • 统一管理:Ports提供了一个集中的地方来管理所有的软件包,软件的安装和维护更加方便。
  • 易于更新:Ports会自动处理依赖关系,确保软件包之间的兼容性,提供自动或手动更新选项。
  • 可定制性:用户可以根据自己的需求对软件包进行定制,例如添加额外的功能或修改配置,针对宿主机的CPU类型和使用方法优化。

构建使用的命令行

下面来实战一下,使用Ports系统构建和安装软件包主要依赖于命令行工具。以下是一些常用的命令及其功能,Ports有意思的点就是,全部功能都是用Makefile实现的:

  1. 如果你安装的时候就选择了Ports,就跳过第1步,如果没有就更新Ports
    cd /usr/ports && make fetchindex
  2. 克隆Ports Tree:
    git clone --depth=1 --branch <你的版本号> https://github.com/freebsd/freebsd-ports /usr/ports
  3. 安装软件,例如vim
    cd /usr/ports/editor/vim && make BATCH=yes install clean
  4. 如果需要搜索可用的软件包,可以用search
    make search key=^vim- | grep -E "Port:|Path:|Info:|^$"
  5. 卸载软件包的话,例如,要卸载vim,可以执行以下命令
    cd /usr/ports/editor/vim
    make deinstall
  6. 使用make clean命令可以清理编译过程中产生的临时文件。
  7. 使用make distclean命令可以清理软件包及其临时文件

参考文章:

RISCV 64 高性能浮点rounding Go实现

引言

RISC-V(下简称RV),作为一种开源的CPU架构,其灵活的指令集和可扩展性为开发者提供了丰富的设计选项。在数值计算中,浮点数的处理尤为重要,而浮点数舍入(rounding)机制则是确保计算精确性和效率的关键一环。本文将聚焦于RV64架构下浮点数的舍入(浮点到浮点)在Go语言中实现,特别是通过FCVTDL/FCVTLD指令的应用来探讨实现的原理。

想看代码的朋友,可以直接看我提交到Go官方的代码参考

golang/go/commit 90391c2

啥是舍入(rounding)

Round(2.5) = 2,就是一种舍入方法(四舍五入嘛)

实际编码中的问题

第一个问题是,既然RV64有浮点转换指令,那直接用不就行了么?

事情并没这么简单,由于RV64并不像其他架构有单独的浮点到浮点的取整指令(例如arm64的FRINTMD),因此只能用FCVT (floating point convert)先转换到整数寄存器中,再从整数寄存器中转回浮点寄存器。

例如浮点值X,在寄存器FA0中,需要以下指令(注:Go的Asm,从左到右):

FCVTLD FA0, A0
FCVTDL A0, FA0

坑就在此出现了!

IEEE 754 中 -Inf (负无穷大)的二进制表达是0x7fffffffffffffff,而根据RV64指令集手册,对于不合格的浮点输入,就“凑到相近的值”并复制到整数寄存器中了。

Floor(-Inf) -> int64(0x7fffffffffffffff)

这下热闹了,整数0x7ff...ff是合法的整数。当你转回浮点时……就变成了float64(9.22e+18)。这意味着

非法数值变成了合法数值

例如这个issue:https://github.com/golang/go/issues/68322

那么通过RV64的FCLASS (浮点类型)指令提前判断呢?可以是可以,但由于多重判断是否数值在取整范围内,经过测试速度不够快(性能下降60%),并不符合我们程序员对于“高效”的追求。如果要达成快捷的判断非法输入的方法,需要我们回顾一下IEEE 754的表达方式。

RV64中浮点数的表示

在RV64浮点数中的表示遵循IEEE 754标准,该标准定义了浮点数的符号位、指数和尾数部分。

IEEE 754标准定义了浮点数在计算机中的存储方式,主要包括三个部分:符号位(S)、指数(E)和尾数(M,也称为有效数字或小数部分)。对于双精度浮点数(即double类型,在大多数现代计算机中占用64位),其格式如下:

  • 符号位(1位):位于最高位,0表示正数,1表示负数。
  • 指数(11位):用于表示浮点数的指数部分,采用偏移量编码方式(对于双精度,偏移量为1023)。
  • 尾数(52位):表示浮点数的有效数字部分,但隐式包含了一个前导的1(除了表示0或次正规数的情况)。

例如要表达IEEE754 DP 0.375,可以拆解为:0.25*1.5

  • 正数,符号位为0
  • 指数需要0.25,2-2,通过补码,即0x3FD
  • 尾数1.5,则是1+2-1,即0x8(1000_0000)b

二进制即0x3FD8_0000_0000_0000

其中IEEE 754 DP非法的输入分别是:

  • ±Inf(正负无穷大)0x7FF0_0000_0000_0000
  • NaN(Not a Number,压根不是个数)

NaN也有很多中表达方式,有

  • qNaN 0x7FF8_0000_0000_0001
  • sNaN 0x7FF0_0000_0000_0001
  • 特殊NaN 0x7FFF_FFFF_FFFF_FFFF

如果仔细留意的话,你会发现,所有的非法输入都是通过指数位表示的,而且都相当大(0x7FF= 2047d - 1023,实际为1024),那么,我们只需要通过右移52位,并加以掩码(mask)去除正负影响,就可以判断一个浮点数是不是非法输入(0x7FF)。重点来了

这个方法可以顺便判断是不是整数取整范围

因为浮点数能取整,就意味着指数小于53,即整个数小于253,如果对大于这个数取整就会出现未定义行为了,所以Go语言限制,必须在这个范围内,超过的合法输入原样输出即可。

var x float64
maskedExp := (math.Float64bits(x) >> 52) & 0x7FF
if maskedExp > 1023 + 52 {
    return x
}
// FCVTLD x, A0
// FCVTDL A0, x

这样是不是就好了?不……还有一个坑……

±0没办法处理

所以最后需要使用RV64的FSGNJD指令,将x中的符号位拷贝复制过来。

最终效果

见前面提到的golang/go/commit 90391c2,提升300%

            │ math.old.bench │           math.new.bench            │
            │     sec/op     │   sec/op     vs base                │
Ceil             54.09n ± 0%   18.72n ± 0%  -65.39% (p=0.000 n=10)
Floor            40.72n ± 0%   18.72n ± 0%  -54.03% (p=0.000 n=10)
Trunc            38.72n ± 0%   18.72n ± 0%  -51.65% (p=0.000 n=10)
geomean          33.56n        20.09n       -40.13%