summaryrefslogtreecommitdiff
path: root/meta-google/recipes-google/ncsi/files/gbmc-ncsi-ip-from-ra.sh.in
blob: 80bd34f04ae506f761fb451766edaea7f6bd6ad3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#!/bin/bash
# Copyright 2021 Google LLC
#
# 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.

source /usr/share/network/lib.sh || exit
source /usr/libexec/ncsid_lib.sh || exit

NCSI_IF='@NCSI_IF@'

old_pfx=
old_fqdn=
old_rtr=

set_host() {
  [ -n "$host" -a -n "$domain" -a -n "$hextet" ] || return

  local fqdn="$host-n$hextet.$domain"
  [ "$fqdn" != "$old_fqdn" ] || return
  old_fqdn="$fqdn"

  echo "Found hostname $fqdn" >&2
  hostnamectl set-hostname "$fqdn" || true
}

set_net() {
  [ -n "$pfx" -a -n "$rtr" ] || return
  [[ "$pfx" != "$old_pfx" || "$rtr" != "$old_rtr" ]] || return
  old_pfx="$pfx"
  old_rtr="$rtr"

  echo "Found prefix $pfx from $rtr" >&2

  # Delete any stale IP Addresses from the primary interface as we won't use them
  UpdateIP xyz.openbmc_project.Network "$NCSI_IF" '0.0.0.0' '0' || true
  UpdateIP xyz.openbmc_project.Network "$NCSI_IF" '::' '0' || true

  read -r -d '' contents <<EOF
[Network]
Address=$pfx/128
IPv6PrefixDelegation=yes
[IPv6PrefixDelegation]
RouterLifetimeSec=60
[IPv6Prefix]
Prefix=$stateless_pfx/80
PreferredLifetimeSec=60
ValidLifetimeSec=60
[IPv6RoutePrefix]
Route=$pfx/80
LifetimeSec=60
[Route]
Destination=$stateless_pfx/76
Type=unreachable
Metric=1024
EOF
  for file in /run/systemd/network/{00,}-bmc-gbmcbr.network.d/49-public-ra.conf; do
    mkdir -p -m 755 "$(dirname "$file")"
    printf '%s' "$contents" >"$file"
  done
  touch -c /lib/systemd/network/*-bmc-gbmcbr.network || true

  contents='[Network]'$'\n'
  contents+="Address=$pfx/128"$'\n'
  contents+="Gateway=$rtr"$'\n'
  for file in /run/systemd/network/{00,}-bmc-"$NCSI_IF".network.d/49-public-ra.conf; do
    mkdir -p -m 755 "$(dirname "$file")"
    printf '%s' "$contents" >"$file"
  done
  touch -c /etc/systemd/network/*-bmc-"$NCSI_IF".network || true

  if [ "$(systemctl is-active systemd-networkd)" != 'inactive' ]; then
    networkctl reload && networkctl reconfigure gbmcbr "$NCSI_IF" || true
  fi

  read -r -d '' contents <<EOF
table inet filter {
  chain ncsi_input {
    ip6 saddr != $pfx/76 ip6 daddr $pfx/76 goto ncsi_gbmc_br_pub_input
  }
  chain ncsi_forward {
    ip6 saddr != $pfx/76 ip6 daddr $pfx/76 accept
  }
}
EOF
  rfile=/run/nftables/40-gbmc-ncsi-ra.rules
  mkdir -p -m 755 "$(dirname "$rfile")"
  printf '%s' "$contents" >"$rfile"
  systemctl reset-failed nftables && systemctl --no-block restart nftables || true
}

w=60
while true; do
  start=$SECONDS
  while read line; do
    if [ -z "$line" ]; then
      hextet=
      pfx=
      host=
      domain=
    elif [[ "$line" =~ ^Prefix' '*:' '*(.*)/([0-9]+)$ ]]; then
      t_pfx="${BASH_REMATCH[1]}"
      t_pfx_len="${BASH_REMATCH[2]}"
      ip_to_bytes t_pfx_b "$t_pfx" || continue
      (( t_pfx_len == 76 && t_pfx_b[8] & 0xfd == 0xfd )) || continue
      (( t_pfx_b[9] |= 1 ))
      hextet="fd$(printf '%02x' ${t_pfx_b[9]})"
      pfx="$(ip_bytes_to_str t_pfx_b)"
      (( t_pfx_b[9] &= 0xf0 ))
      stateless_pfx="$(ip_bytes_to_str t_pfx_b)"
    elif [[ "$line" =~ ^'DNS search list'' '*:' '*([^.-]*)[^.]*[.](.*.google.com)$ ]]; then
      host="${BASH_REMATCH[1]}"
      domain="${BASH_REMATCH[2]}"
    elif [[ "$line" =~ ^from' '(.*)$ ]]; then
      rtr="${BASH_REMATCH[1]}"
      set_net || true
      set_host || true
    fi
  done < <(rdisc6 -d -m "$NCSI_IF" -w $(( w * 1000 )) 2>/dev/null)
  # If rdisc6 exits early we still want to wait the full `w` time before
  # starting again.
  (( timeout = start + w - SECONDS ))
  sleep $(( timeout < 0 ? 0 : timeout ))
done