Skip to content

Commit

Permalink
bpf: Improve reply datapath in daens
Browse files Browse the repository at this point in the history
Now reply traffic will be routed to lo, then lo_egress bpf redirects
packets to lo_ingress bpf, where bpf_redirect_peer will be called to
pass packets to host.

This also leaves neighbor system bypassed because routing destination lo
requires no L2 header filling.
  • Loading branch information
jschwinger233 committed Mar 2, 2024
1 parent d12323b commit 773bc69
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 40 deletions.
2 changes: 2 additions & 0 deletions control/bpf_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,13 +226,15 @@ retryLoadBpf:
tproxyPort uint32
controlPlanePid uint32
dae0Ifindex uint32
dae0peerIfindex uint32
dae0NetnsId uint32
dae0peerMac [6]byte
padding [2]byte
}{
tproxyPort: uint32(opts.BigEndianTproxyPort),
controlPlanePid: uint32(os.Getpid()),
dae0Ifindex: uint32(GetDaeNetns().Dae0().Attrs().Index),
dae0peerIfindex: uint32(GetDaeNetns().Dae0Peer().Attrs().Index),
dae0NetnsId: uint32(netnsID),
dae0peerMac: [6]byte(GetDaeNetns().Dae0Peer().Attrs().HardwareAddr),
},
Expand Down
65 changes: 65 additions & 0 deletions control/control_plane_core.go
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,71 @@ func (c *controlPlaneCore) _bindWan(ifname string) error {
func (c *controlPlaneCore) bindDaens() (err error) {
daens := GetDaeNetns()

// lo inside daens
daens.With(func() error {
return c.addQdisc("lo")
})

filterLoIngress := &netlink.BpfFilter{
FilterAttrs: netlink.FilterAttrs{
LinkIndex: consts.LoopbackIfIndex,
Parent: netlink.HANDLE_MIN_INGRESS,
Handle: netlink.MakeHandle(0x2022, 0b010+uint16(c.flip)),
Protocol: unix.ETH_P_ALL,
Priority: 0,
},
Fd: c.bpf.bpfPrograms.TproxyDaensLoIngress.FD(),
Name: consts.AppName + "_lo_ingress",
DirectAction: true,
}
daens.With(func() error {
return netlink.FilterDel(filterLoIngress)
})
// Remove and add.
if !c.isReload {
// Clean up thoroughly.
filterIngressFlipped := deepcopy.Copy(filterLoIngress).(*netlink.BpfFilter)
filterIngressFlipped.FilterAttrs.Handle ^= 1
daens.With(func() error {
return netlink.FilterDel(filterLoIngress)
})
}
if err = daens.With(func() error {
return netlink.FilterAdd(filterLoIngress)
}); err != nil {
return fmt.Errorf("cannot attach ebpf object to filter ingress: %w", err)
}

filterLoEgress := &netlink.BpfFilter{
FilterAttrs: netlink.FilterAttrs{
LinkIndex: consts.LoopbackIfIndex,
Parent: netlink.HANDLE_MIN_EGRESS,
Handle: netlink.MakeHandle(0x2023, 0b100+uint16(c.flip)),
Protocol: unix.ETH_P_ALL,
Priority: 2,
},
Fd: c.bpf.bpfPrograms.TproxyDaensLoEgress.FD(),
Name: consts.AppName + "_lo_egress",
DirectAction: true,
}
daens.With(func() error {
return netlink.FilterDel(filterLoEgress)
})
// Remove and add.
if !c.isReload {
// Clean up thoroughly.
filterEgressFlipped := deepcopy.Copy(filterLoEgress).(*netlink.BpfFilter)
filterEgressFlipped.FilterAttrs.Handle ^= 1
daens.With(func() error {
return netlink.FilterDel(filterEgressFlipped)
})
}
if err := daens.With(func() error {
return netlink.FilterAdd(filterLoEgress)
}); err != nil {
return fmt.Errorf("cannot attach ebpf object to filter egress: %w", err)
}

// tproxy_dae0peer_ingress@eth0 at dae netns
daens.With(func() error {
return c.addQdisc(daens.Dae0Peer().Attrs().Name)
Expand Down
11 changes: 11 additions & 0 deletions control/kern/tproxy.c
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ struct dae_param {
__u32 tproxy_port;
__u32 control_plane_pid;
__u32 dae0_ifindex;
__u32 dae0peer_ifindex;
__u32 dae_netns_id;
__u8 dae0peer_mac[6];
__u8 padding[2];
Expand Down Expand Up @@ -1068,6 +1069,16 @@ int tproxy_lan_ingress(struct __sk_buff *skb) {
return TC_ACT_SHOT;
}

SEC("tc/daens_lo_egress")
int tproxy_daens_lo_egress(struct __sk_buff *skb) {
return bpf_redirect(skb->ifindex, BPF_F_INGRESS);
}

SEC("tc/daens_lo_ingress")
int tproxy_daens_lo_ingress(struct __sk_buff *skb) {
return bpf_redirect_peer(PARAM.dae0peer_ifindex, 0);
}

// Cookie will change after the first packet, so we just use it for
// handshake.
static __always_inline bool pid_is_control_plane(struct __sk_buff *skb,
Expand Down
51 changes: 11 additions & 40 deletions control/netns_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,42 +307,22 @@ func (ns *DaeNetns) setupIPv4Datapath() (err error) {
}
defer netns.Set(ns.hostNs)

// (ip net e daens) ip a a 169.254.0.11 dev dae0peer
// Although transparent UDP socket doesn't use this IP, it's still needed to make proper L3 header
ip, ipNet, err := net.ParseCIDR("169.254.0.11/32")
// (ip net e daens) ip a a 169.254.0.1 dev dae0peer
ip, ipNet, err := net.ParseCIDR("169.254.0.1/32")
ipNet.IP = ip
if err != nil {
return fmt.Errorf("failed to parse ip 169.254.0.11: %v", err)
return fmt.Errorf("failed to parse ip 169.254.0.1: %v", err)
}
if err = netlink.AddrAdd(ns.dae0peer, &netlink.Addr{IPNet: ipNet}); err != nil {
return fmt.Errorf("failed to add v4 addr to dae0peer: %v", err)
}
// (ip net e daens) ip r a 169.254.0.1 dev dae0peer
// 169.254.0.1 is the link-local address used for ARP caching
if err = netlink.RouteAdd(&netlink.Route{
LinkIndex: ns.dae0peer.Attrs().Index,
Dst: &net.IPNet{IP: net.ParseIP("169.254.0.1"), Mask: net.CIDRMask(32, 32)},
Gw: nil,
Scope: netlink.SCOPE_LINK,
}); err != nil {
return fmt.Errorf("failed to add v4 route1 to dae0peer: %v", err)
}
// (ip net e daens) ip r a default via 169.254.0.1 dev dae0peer
if err = netlink.RouteAdd(&netlink.Route{
LinkIndex: ns.dae0peer.Attrs().Index,
// (ip net e daens) ip r r default dev lo
if err = netlink.RouteReplace(&netlink.Route{
LinkIndex: consts.LoopbackIfIndex,
Dst: &net.IPNet{IP: net.IPv4(0, 0, 0, 0), Mask: net.CIDRMask(0, 32)},
Gw: net.ParseIP("169.254.0.1"),
}); err != nil {
return fmt.Errorf("failed to add v4 route2 to dae0peer: %v", err)
}
// (ip net e daens) ip n r 169.254.0.1 dev dae0peer lladdr $mac_dae0 nud permanent
if err = netlink.NeighSet(&netlink.Neigh{
IP: net.ParseIP("169.254.0.1"),
HardwareAddr: ns.dae0.Attrs().HardwareAddr,
LinkIndex: ns.dae0peer.Attrs().Index,
State: netlink.NUD_PERMANENT,
Gw: nil,
}); err != nil {
return fmt.Errorf("failed to add neigh to dae0peer: %v", err)
return fmt.Errorf("failed to add default dev lo: %v", err)
}
return
}
Expand All @@ -364,23 +344,14 @@ func (ns *DaeNetns) setupIPv6Datapath() (err error) {
}
defer netns.Set(ns.hostNs)

// (ip net e daens) ip -6 r a default via fe80::ecee:eeff:feee:eeee dev dae0peer
// (ip net e daens) ip -6 r a default dev lo
if err = netlink.RouteAdd(&netlink.Route{
LinkIndex: ns.dae0peer.Attrs().Index,
LinkIndex: consts.LoopbackIfIndex,
Dst: &net.IPNet{IP: net.IPv6zero, Mask: net.CIDRMask(0, 128)},
Gw: net.ParseIP("fe80::ecee:eeff:feee:eeee"),
Gw: nil,
}); err != nil {
return fmt.Errorf("failed to add v6 route to dae0peer: %v", err)
}
// (ip net e daens) ip n r fe80::ecee:eeff:feee:eeee dev dae0peer lladdr $mac_dae0 nud permanent
if err = netlink.NeighSet(&netlink.Neigh{
IP: net.ParseIP("fe80::ecee:eeff:feee:eeee"),
HardwareAddr: ns.dae0.Attrs().HardwareAddr,
LinkIndex: ns.dae0peer.Attrs().Index,
State: netlink.NUD_PERMANENT,
}); err != nil {
return fmt.Errorf("failed to add neigh to dae0peer: %v", err)
}
return
}

Expand Down

0 comments on commit 773bc69

Please sign in to comment.