| #!/usr/bin/env bash |
| # Licensed to the Apache Software Foundation (ASF) under one |
| # or more contributor license agreements. See the NOTICE file |
| # distributed with this work for additional information |
| # regarding copyright ownership. The ASF licenses this file |
| # to you 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. |
| |
| # modifymacip.sh -- Manage static ARP/NDP entries and host routes for VM NICs |
| # |
| # Usage: |
| # add: modifymacip.sh -o add -b <bridge> -m <mac> [-4 <ipv4>] ... [-6 <ipv6>] ... |
| # delete: modifymacip.sh -o delete -b <bridge> -m <mac> |
| # |
| # Both -4 and -6 may be specified multiple times to cover primary and secondary |
| # addresses (e.g. link-local + global unicast for IPv6). |
| # On delete the bridge neighbour table is queried for all entries matching the |
| # MAC address; no separate state file is required. |
| |
| usage() { |
| echo "Usage: $0 -o <add|delete> -b <bridge> -m <mac> [-4 <ipv4>] ... [-6 <ipv6>] ..." |
| } |
| |
| OP= |
| BRIDGE= |
| MAC= |
| IPV4_LIST=() |
| IPV6_LIST=() |
| |
| while getopts 'o:b:m:4:6:' OPTION; do |
| case $OPTION in |
| o) OP="$OPTARG" ;; |
| b) BRIDGE="$OPTARG" ;; |
| m) MAC="$OPTARG" ;; |
| 4) IPV4_LIST+=("$OPTARG") ;; |
| 6) IPV6_LIST+=("$OPTARG") ;; |
| ?) usage; exit 2 ;; |
| esac |
| done |
| |
| if [[ -z "$OP" || -z "$BRIDGE" || -z "$MAC" ]]; then |
| usage |
| exit 2 |
| fi |
| |
| add_entries() { |
| for addr in "${IPV4_LIST[@]}"; do |
| ip neigh replace "${addr}" lladdr "${MAC}" dev "${BRIDGE}" nud permanent |
| ip route replace "${addr}/32" dev "${BRIDGE}" |
| done |
| |
| if [[ "${#IPV6_LIST[@]}" -gt 0 ]]; then |
| # Ensure IPv6 is enabled on the bridge before installing NDP entries |
| sysctl -qw "net.ipv6.conf.${BRIDGE}.disable_ipv6=0" |
| for addr in "${IPV6_LIST[@]}"; do |
| ip -6 neigh replace "${addr}" lladdr "${MAC}" dev "${BRIDGE}" nud permanent |
| ip -6 route replace "${addr}/128" dev "${BRIDGE}" |
| done |
| fi |
| } |
| |
| delete_entries() { |
| # Find all IPv4 neighbour entries on the bridge matching this MAC and remove them |
| while read -r addr; do |
| ip neigh del "${addr}" dev "${BRIDGE}" 2>/dev/null || true |
| ip route del "${addr}/32" dev "${BRIDGE}" 2>/dev/null || true |
| done < <(ip neigh show dev "${BRIDGE}" | awk -v mac="${MAC}" 'tolower($3) == tolower(mac) {print $1}') |
| |
| # Find all IPv6 neighbour entries on the bridge matching this MAC and remove them |
| while read -r addr; do |
| ip -6 neigh del "${addr}" dev "${BRIDGE}" 2>/dev/null || true |
| ip -6 route del "${addr}/128" dev "${BRIDGE}" 2>/dev/null || true |
| done < <(ip -6 neigh show dev "${BRIDGE}" | awk -v mac="${MAC}" 'tolower($3) == tolower(mac) {print $1}') |
| } |
| |
| case "$OP" in |
| add) add_entries ;; |
| delete) delete_entries ;; |
| *) usage; exit 2 ;; |
| esac |