#!/bin/sh # Copyright (c) 2015 Rozhuk Ivan # All rights reserved. # # Subject to the following obligations and disclaimer of warranty, use and # redistribution of this software, in source or object code forms, with or # without modifications are expressly permitted by Whistle Communications; # provided, however, that: # 1. Any and all reproductions of the source or object code must include the # copyright notice above and the following disclaimer of warranties; and # 2. No rights are granted, in any manner or form, to use Whistle # Communications, Inc. trademarks, including the mark "WHISTLE # COMMUNICATIONS" on advertising, endorsements, or otherwise except as # such appears in the above copyright notice or in the software. # # THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND # TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO # REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, # INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. # WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY # REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS # SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. # IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES # RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING # WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, # PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR # SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY # OF SUCH DAMAGE. # # Author: Rozhuk Ivan # # This script creates LAGG interface using netgraph nodes. # Roundrobin algo used. # History # # Version: 1.0 # * initial release usage_msg() { echo "usage:" echo "" echo " Create new netgraph LAGG interface named \"NEW_NG_LAGG_IF_NAME\"" echo "and add interfaces: \"ifname1\" \"ifname2\"..." echo "NEW_NG_LAGG_IF_NAME = \"auto\" - automatic generate names: \"ngeht0\", \"ngeth1\"..." echo " start NEW_NG_LAGG_IF_NAME ifname1 ifname2..." echo " start auto ifname1 ifname2..." echo "" echo " Destroy netgraph LAGG interface named \"NG_LAGG_IF_NAME\":" echo " stop NG_LAGG_IF_NAME" echo "" echo " Add interface \"ifname\" to netgraph LAGG interface named \"NG_LAGG_IF_NAME\":" echo " if_add NG_LAGG_IF_NAME ifname" echo "" echo " Remove interface \"ifname\" from netgraph LAGG interface:" echo " if_del ifname" } case $1 in start) # Load modules. kldload ng_ether > /dev/null 2>&1 kldload ng_one2many > /dev/null 2>&1 IF_NAME=$3 # Check first network interface. if [ -z ${IF_NAME} ]; then echo "Network interface name required." usage_msg return 1 fi if ! ifconfig ${IF_NAME} up > /dev/null 2>&1 ; then echo "Invalid network interface name: ${IF_NAME}." usage_msg return 1 fi # Create and connect nodes fo first network interface. ## Init network interface. ngctl msg ${IF_NAME}: setpromisc 1 ngctl msg ${IF_NAME}: setautosrc 0 ## Nodes create. ngctl mkpeer ${IF_NAME}: one2many lower many0 ngctl mkpeer ${IF_NAME}:lower eiface one ether NG_EIFACE_IF_NAME=`ngctl msg ${IF_NAME}:lower.one getifname | grep Args: | tail -c +8 | rev | tail -c +2 | rev` ## Rename nodes and LAGG interface. if [ $2 = "auto" ]; then NG_LAGG_IF_NAME=${NG_EIFACE_IF_NAME} else NG_LAGG_IF_NAME=$2 ngctl name "${IF_NAME}":lower.one "${NG_LAGG_IF_NAME}" ifconfig "${NG_EIFACE_IF_NAME}" name "${NG_LAGG_IF_NAME}" fi ## Rename one2many node. ONE2MANY_NAME="${NG_LAGG_IF_NAME}-one2many" ngctl name "${IF_NAME}":lower "${ONE2MANY_NAME}" ## Generate and set mac on LAGG interface. IF_NG_LAGG_MAC=`head -c 16 /dev/random | md5 | tail -c 11` ifconfig ${NG_LAGG_IF_NAME} link "00${IF_NG_LAGG_MAC}" down up ## Add other network interfaces to LAGG. ### many0 allready used, start from 1. HOOK_NUM=1 ### Start from second interface name / skeep first 3 args. shift 3 while [ "$#" -gt 0 ]; do CUR_ARG=$1 ### Move to next command line arg. shift 1 if ! ifconfig ${CUR_ARG} up > /dev/null 2>&1 ; then echo "Invalid network interface name: ${CUR_ARG}." else ## Init network interface and connect to LAGG. ngctl msg ${CUR_ARG}: setpromisc 1 ngctl msg ${CUR_ARG}: setautosrc 0 ngctl connect ${CUR_ARG}: ${ONE2MANY_NAME}: lower "many${HOOK_NUM}" let HOOK_NUM=HOOK_NUM+1 > /dev/null 2>&1 fi done ;; stop) NG_LAGG_IF_NAME=$2 # Check first network interface name. if [ -z ${NG_LAGG_IF_NAME} ]; then echo "LAGG interface name required." usage_msg return 1 fi if ! ifconfig ${NG_LAGG_IF_NAME} > /dev/null 2>&1 ; then echo "Invalid LAGG interface name: ${NG_LAGG_IF_NAME}." usage_msg return 1 fi ONE2MANY_NAME="${NG_LAGG_IF_NAME}-one2many" # Configure network interface to default settings. for i in $(jot - 0 64); do ngctl msg ${ONE2MANY_NAME}:"many$i" setautosrc 1 > /dev/null 2>&1 ngctl msg ${ONE2MANY_NAME}:"many$i" setpromisc 0 > /dev/null 2>&1 done # Remove hooks and nodes. ngctl shutdown ${ONE2MANY_NAME}: ngctl shutdown ${NG_LAGG_IF_NAME}: ;; if_add) NG_LAGG_IF_NAME=$2 # Check LAGG network interface name. if [ -z ${NG_LAGG_IF_NAME} ]; then echo "LAGG interface name required." usage_msg return 1 fi if ! ifconfig ${NG_LAGG_IF_NAME} > /dev/null 2>&1 ; then echo "Invalid LAGG interface name: ${NG_LAGG_IF_NAME}." usage_msg return 1 fi IF_NAME=$3 # Check network interface. if [ -z ${IF_NAME} ]; then echo "Network interface required." usage_msg return 1 fi if ! ifconfig ${IF_NAME} up > /dev/null 2>&1 ; then echo "Invalid interface name: ${IF_NAME}." usage_msg return 1 fi ONE2MANY_NAME="${NG_LAGG_IF_NAME}-one2many" # Configure network interface. ngctl msg ${IF_NAME}: setautosrc 1 ngctl msg ${IF_NAME}: setpromisc 0 for i in $(jot - 0 6); do if ngctl connect ${IF_NAME}: ${ONE2MANY_NAME}: lower "many$i" > /dev/null 2>&1 ; then # OK, added! return 0 fi done echo "Add \"${IF_NAME}\" to \"${NG_LAGG_IF_NAME}\" FAIL: no more free links in LAGG (max 64) or \"${IF_NAME}\" allready connected." return 1 ;; if_del) IF_NAME=$2 # Check network interface. if [ -z ${IF_NAME} ]; then echo "Network interface name required." usage_msg return 1 fi if ! ifconfig ${IF_NAME} up > /dev/null 2>&1 ; then echo "Invalid interface name: ${IF_NAME}." usage_msg return 1 fi # configure net if ngctl msg ${IF_NAME}: setautosrc 1 ngctl msg ${IF_NAME}: setpromisc 0 # remove hooks and nodes ngctl rmhook ${IF_NAME}: lower # TODO: check is last iface removed and call stop. ;; *) echo "Unknown command: \"$1\"" usage_msg esac return 0