diff --git a/README.md b/README.md index 5c71e13..acb252c 100644 --- a/README.md +++ b/README.md @@ -18,22 +18,41 @@ You should install docker before following. $ sudo apt install python3 python3-pip graphviz $ git clone https://github.com/slankdev/tinet && cd tinet $ sudo pip3 install -r requirement.txt -$ sudo cp bin/tn /usr/local/tn +$ sudo cp bin/tn /usr/local/bin/tn $ tn version ``` -Usage: ``` -$ cd -$ tn // show usage -$ tn -h // show help -$ tn init // generate init shell-script to stdout -$ tn fini // generate fini shell-script to stdout -$ tn init | sudo sh // generate and execute init shell-script -$ tn fini | sudo sh // generate and execute fnit shell-script -$ tn conf | sudo sh // generate and execute config shell-script -$ tn tpl // generate template -$ tn img // generate network topology image file +Usage: + tn [-f ...] [options] [COMMAND] [ARGS...] + tn -h|--help + +Options: + --verbose Generate verbose shell + --dry-run Print the recipes that are needed to execute the + targets up to date, but not actually execute them. + --project-name NAME Specify an alternate project name + (default: none) + --H, --host HOST Daemon socket to connect to + +COMMAND: + ps List services + start Start services + stop Stop services + create Create services + rm Remove stopped containers + up Create and start containers + down Stop and remove containers + pull Pull service images + exec Execute a command in a running container + build Generate a Docker bundle from the spec file + conf Execute config-cmd in a running container + reconf Remove, create, start and config + restart Remove, create, start + version Show the tinet version information + test Execute tests + init Generate template spec file + img Generate topology png file ``` Running on VM diff --git a/bin/main.py b/bin/main.py new file mode 100755 index 0000000..a607c98 --- /dev/null +++ b/bin/main.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 + +import sys +import getopt +import argparse +import pprint +import pydot +import yaml + +usage_text=''' + tn [-f ...] [options] [COMMAND] [ARGS...] + tn -h|--help + +Options: + -f --specfile NAME Specify specification yaml file + -v, --verbose Generate verbose shell + --dry-run Print the recipes that are needed to execute the + targets up to date, but not actually execute them. + --project-name NAME Specify an alternate project name + (default: none) + --host HOST Daemon socket to connect to + +COMMAND: + ps List services + up Create and start containers + down Stop and remove containers + pull Pull service images + exec Execute a command in a running container + build Generate a Docker bundle from the spec file + conf Execute config-cmd in a running container + reconf Stop, remove, create, start and config + reup Stop, remove, create and start + version Show the tinet version information + test Execute tests + init Generate template spec file + img Generate topology png file +''' + +def command_exec(args): + print('command_exec') + print(args) + +def command_conf(args): + print('command_conf') + print(args) + +def main(): + parser = argparse.ArgumentParser( + formatter_class=argparse.RawTextHelpFormatter) + parser.add_argument('-f', '--specfile', default='spec.yaml') + parser.add_argument('-H', '--host', default=None) + parser.add_argument('--project-name', default='') + parser.add_argument('--verbose', action='store_true') + + subparsers = parser.add_subparsers(dest='command') + subparsers.required = True + + exec_parser = subparsers.add_parser('exec', help='see add exec') + exec_parser.add_argument('target') + exec_parser.set_defaults(func=command_exec) + + exec_parser = subparsers.add_parser('conf', help='see add conf') + exec_parser.set_defaults(func=command_conf) + + args = parser.parse_args() + args.func(args) + +main() diff --git a/bin/tn b/bin/tn index b1d9ff9..732b7e2 100755 --- a/bin/tn +++ b/bin/tn @@ -1,506 +1,639 @@ #!/usr/bin/env python3 import sys -import yaml -import pprint +import getopt import argparse +import pprint import pydot +import yaml + +class AppInfo: + verbose = False + host = None + name = '' + specfile = '' + version = 'TiNet version 0.0 alpha' + command = '' + data = [] + def __init__(self): + self.specfile = 'spec.yaml' + self.verbose = False + self.host = None + self.name = '' + self.command = 'version' + if self.host != None: + sys.stderr.write('remote host isn\'t supported.\n') + sys.exit(1) + if self.name != '': + sys.stderr.write('project-name isn\'t supported.\n') + sys.exit(1) +appinfo = AppInfo() + +template_spec=''' +nodes: + - name: C0 + type: docker #optional (default:docker) + image: slankdev/ubuntu:18.04 + interfaces: + - { name: net0, type: direct, args: C1#net0 } + - { name: net1, type: bridge, args: B0 } + - { name: net2, type: phys } + - name: C1 + type: netns #optional (default:docker) + interfaces: + - { name: net0, type: direct, args: C0#net0 } + - { name: net1, type: bridge, args: B0 } + +switches: + - name: B0 + interfaces: + - { name: net0, type: docker, args: C0 } + - { name: net0, type: netns, args: C0 } + +node_configs: + - name: C0 + cmds: + - cmd: ip link set dev net0 up + - name: C1 + cmds: + - cmd: echo slankdev slankdev + - cmd: >- + echo slankdev && + echo slnakdev + +test: + - cmds: + - cmd: docker exec C0 ping -c2 10.0.0.2 + - cmd: echo slankdev slankdev +''' + +text__mount_docker_netns=''' +mount_docker_netns () { + if [ $# -ne 2 ]; then + echo "Usage: $0 " + exit 1 + fi + mkdir -p /var/run/netns + PID=`docker inspect $1 -f "{{.State.Pid}}"` + ln -s /proc/$PID/ns/net /var/run/netns/$2 +} +''' + +text__kokobr=''' +kokobr () { + if [ $# -ne 3 ]; then + echo "Usage: $0 " + exit 1 + fi + mount_docker_netns $2 $2 + ip link add name $3 type veth peer name $2$3 + ip link set dev $3 netns $2 + ip link set $2$3 up + ip netns exec $2 ip link set $3 up + ip netns del $2 + ovs-vsctl add-port $1 $2$3 +} +''' + +text__kokobr_netns=''' +kokobr_netns () { + if [ $# -ne 3 ]; then + echo "Usage: $0 " + exit 1 + fi + ip link add name $3 type veth peer name $2$3 + ip link set dev $3 netns $2 + ip link set $2$3 up + ip netns exec $2 ip link set $3 up + ovs-vsctl add-port $1 $2$3 +} +''' + +text__koko_physnet =''' +koko_physnet () { +if [ $# -ne 2 ]; then + echo "Usage: $0 " + exit 1 +fi +mount_docker_netns $1 $1 +ip link set dev $2 netns $1 +ip netns exec $1 ip link set $2 up +ip netns del $1 +} +''' + +text__detach_physif_from_docker=''' +detach_physif_from_docker () { +if [ $# -ne 2 ]; then + echo "Usage: $0 " + exit 1 +fi +mount_docker_netns $1 $1 +ip netns exec $1 ip link set $2 netns 1 +ip netns del $1 +} +''' def generate_mount_docker_netns(): - p = print - p('mount_docker_netns () { ') - p(' if [ $# -ne 2 ]; then ') - p(' echo "Usage: $0 " ') - p(' exit 1 ') - p(' fi ') - p(' mkdir -p /var/run/netns ') - p(' PID=`docker inspect $1 -f "{{.State.Pid}}"` ') - p(' ln -s /proc/$PID/ns/net /var/run/netns/$2 ') - p('} ') + print(text__mount_docker_netns) def generate_kokobr(): - p = print - p('kokobr () { ') - p(' if [ $# -ne 3 ]; then ') - p(' echo "Usage: $0 " ') - p(' exit 1 ') - p(' fi ') - p(' mount_docker_netns $2 $2 ') - p(' ip link add name $3 type veth peer name $2$3') - p(' ip link set dev $3 netns $2 ') - p(' ip link set $2$3 up ') - p(' ip netns exec $2 ip link set $3 up ') - p(' ip netns del $2 ') - p(' ovs-vsctl add-port $1 $2$3 ') - p('} ') + print(text__kokobr) def generate_kokobr_netns(): - p = print - p('kokobr_netns () { ') - p(' if [ $# -ne 3 ]; then ') - p(' echo "Usage: $0 " ') - p(' exit 1 ') - p(' fi ') - p(' ip link add name $3 type veth peer name $2$3') - p(' ip link set dev $3 netns $2 ') - p(' ip link set $2$3 up ') - p(' ip netns exec $2 ip link set $3 up ') - p(' ovs-vsctl add-port $1 $2$3 ') - p('} ') + print(text__kokobr_netns) def generate_koko_physnet(): - p = print - p('koko_physnet () { ') - p(' if [ $# -ne 2 ]; then ') - p(' echo "Usage: $0 "') - p(' exit 1 ') - p(' fi ') - p(' mount_docker_netns $1 $1 ') - p(' ip link set dev $2 netns $1 ') - p(' ip netns exec $1 ip link set $2 up ') - p(' ip netns del $1 ') - p('} ') + print(text__koko_physnet) def generate_detach_physif_from_docker(): - p = print - p('detach_physif_from_docker () { ') - p(' if [ $# -ne 2 ]; then ') - p(' echo "Usage: $0 "') - p(' exit 1 ') - p(' fi ') - p(' mount_docker_netns $1 $1 ') - p(' ip netns exec $1 ip link set $2 netns 1') - p(' ip netns del $1 ') - p('} ') - -def tpl(): - p = print - p('nodes: ') - p(' - name: C0 ') - p(' image: slankdev/ubuntu:16.04 ') - p(' interfaces: ') - p(' - { name: net0, type: direct, opts: C1#net0 }') - p(' - name: C0 ') - p(' image: slankdev/ubuntu:16.04 ') - p(' interfaces: ') - p(' - { name: net0, type: direct, opts: C0#net0 }') - p(' ') - p('switches: ') - p(' - name: B0 ') - p(' interfaces: ') - p(' - { name: net0, type: container, opts: C0 } ') - p(' ') - p('node_configs: ') - p(' - name: C0 ') - p(' cmds: ') - p(' - cmd: ip link set dev net0 up ') - p(' - cmd: >- ') - p(' vtysh -c "conf t" ') - p(' -c "router bgp 100 " ') - p(' -c " bgp router-id 2.2.2.2 " ') - p(' ') - p(' - name: C0 ') - p(' cmds: ') - p(' - cmd: echo slankdev slankdev ') - p('test: ') - p(' - cmds: ') - p(' - cmd: docker exec C0 ping -c2 10.0.0.2 ') - - -def preinit(data): + print(text__detach_physif_from_docker) + +def command_ps(args): + print('docker ps --format "table {{.ID}}\\t{{.Names}}"') + +def command_up(args): + def preinit(): print('\n#####################') print('# PRE-INIT COMMANDS #') print('#####################') - if 'preinit' in data: - for node in data['preinit']: - for cmd in node['cmds']: - print('{}'.format(cmd['cmd'])) + if 'preinit' in appinfo.data: + for node in appinfo.data['preinit']: + for cmd in node['cmds']: + print('{}'.format(cmd['cmd'])) -def postinit(data): + def postinit(): print('\n#####################') print('# POST-INIT COMMANDS #') print('#####################') - if 'postinit' in data: - for node in data['postinit']: - for cmd in node['cmds']: - print('{}'.format(cmd['cmd'])) + if 'postinit' in appinfo.data: + for node in appinfo.data['postinit']: + for cmd in node['cmds']: + print('{}'.format(cmd['cmd'])) + + generate_mount_docker_netns() + generate_kokobr() + generate_kokobr_netns() + generate_koko_physnet() + preinit() + + print('\n#####################') + print('# INIT COMMANDS #') + print('#####################') + + # CREATE NODES + print('\n# generate nodes') + if 'nodes' in appinfo.data: + for node in appinfo.data['nodes']: + nodetype = node.get('type', 'docker') + if nodetype == 'docker': + print('docker run -td --hostname {} ' + '--name {} --rm --privileged {}' + .format(node['name'], node['name'], + node['image'])) + elif nodetype == 'netns': + print('ip netns add {}'.format(node['name'])) + else: + print('unknown node-type {}'.format(node['type'])) + sys.exit(1) + + # CREATE SWITCHES + if 'switches' in appinfo.data: + for sw in appinfo.data['switches']: + print('ovs-vsctl add-br {} && ip link set {} up'.format(sw['name'], sw['name'])); + + links = [] + # CREATE Node to Node LINKS + class n2n_link: + left_node_name = None + left_iface_name = None + left_isset = False + left_node_type = None + right_node_name = None + right_iface_name = None + right_isset = False + right_node_type = None + def __init__(self, ln_name, ln_iface, rn_name=None, rn_iface=None): + self.left_node_name = ln_name + self.left_iface_name = ln_iface + self.right_node_name = rn_name + self.right_iface_name = rn_iface + self.left_isset = True + def koko(self): + # EXAMPLE: + # sudo ip link add net0 netns C0 type veth \ + # peer name net0 netns C1 + print('\n# connect {} to {}'.format(self.left_node_name, self.right_node_name)) + if self.left_node_type == 'docker': + print('mount_docker_netns {} {}'.format( + self.left_node_name, self.left_node_name)) + if self.right_node_type == 'docker': + print('mount_docker_netns {} {}'.format( + self.right_node_name, self.right_node_name)) + print('ip link add {} netns {} type veth peer name {} netns {}'.format( + self.left_iface_name, + self.left_node_name, + self.right_iface_name, + self.right_node_name)) + print('ip netns exec {} ip link set {} up'.format( + self.left_node_name, self.left_iface_name)) + print('ip netns exec {} ip link set {} up'.format( + self.right_node_name, self.right_iface_name)) + if self.left_node_type == 'docker': + print('ip netns del {}'.format(self.left_node_name)) + if self.right_node_type == 'docker': + print('ip netns del {}'.format(self.right_node_name)) + def check(self): + if not (self.right_isset and self.left_isset): + Exception('n2n_link state is not correct') + + if 'nodes' in appinfo.data: + for node in appinfo.data['nodes']: + for i in range(len(node['interfaces'])): + iface = node['interfaces'][i] + if (iface['type']=='direct'): + r_nname = iface['args'].split('#')[0] + r_ifname = iface['args'].split('#')[1] + peer_found = False + for link in links: + if link.right_isset == False: + b0 = link.left_node_name == r_nname + b1 = link.left_iface_name == r_ifname + if b0 and b1: # found peer + link.right_node_name = node['name'] + link.right_iface_name = iface['name'] + link.right_node_type = node.get('type', 'docker') + link.right_isset = True + peer_found = True + if peer_found == False: + new_link = n2n_link(node['name'], iface['name'], r_nname, r_ifname) + new_link.left_node_type = node.get('type', 'docker') + links.append(new_link) + for link in links: + link.check() + link.koko() + + links = [] + # CREATE Node to Switch LINKS + class s2n_link: + node_name = None + node_iface = None + node_isset = False + node_type = None + switch_name = None + switch_isset = False + def __init__(self, n_name, n_iface, n_type, s_name): + self.node_name = n_name + self.node_iface = n_iface + self.node_type = n_type + self.switch_name = s_name + + def koko(self): + if self.node_type == 'docker': + print('kokobr {} {} {}'.format(self.switch_name, self.node_name, self.node_iface)) + elif self.node_type == 'netns': + print('kokobr_netns {} {} {}'.format(self.switch_name, self.node_name, self.node_iface)) + else: + print('unknown node-type {}'.format(self.node_type)) + + def check(self): + if not (self.node_isset and self.switch_isset): + Exception('s2n_link state is not correct') + + if ('nodes' in appinfo.data) and ('switches' in appinfo.data): + for node in appinfo.data['nodes']: + for i in range(len(node['interfaces'])): + iface = node['interfaces'][i] + if (iface['type']=='bridge'): + print('\n# connect {} and {}' + .format(node['name'], iface['args'])) + new_link = s2n_link(node['name'], iface['name'], + node.get('type', 'docker'), iface['args']) + new_link.node_isset = True + new_link.switch_isset = False + links.append(new_link) + for sw in appinfo.data['switches']: + for i in range(len(sw['interfaces'])): + iface = sw['interfaces'][i] + for link in links: + if link.switch_isset == False: + b0 = iface['args'] == link.node_name + b1 = iface['name'] == link.node_iface + b2 = sw['name'] == link.switch_name + if b0 and b1 and b2: + link.switch_isset = True + for link in links: + link.check() + link.koko() + + # Attach PhysNetIf to Conitaner + if 'nodes' in appinfo.data: + for node in appinfo.data['nodes']: + for i in range(len(node['interfaces'])): + iface = node['interfaces'][i] + if (iface['type']=='phys'): + print('koko_physnet {} {}'.format(node['name'], iface['name'])) + + # Attach raw veth to Conitaner + if 'nodes' in appinfo.data: + for node in appinfo.data['nodes']: + for i in range(len(node['interfaces'])): + iface = node['interfaces'][i] + if (iface['type']=='veth'): + print('ip link add {} type veth peer name {}'.format( + iface['name'], iface['args'])) + print('koko_physnet {} {}'.format(node['name'], iface['name'])) + print('ip link set {} up'.format(iface['args'])) + postinit() + +def command_down(args): + def prefini(): + print('\n#####################') + print('# PRE-FINI COMMANDS #') + print('#####################') + if 'prefini' in appinfo.data: + for node in appinfo.data['prefini']: + for cmd in node['cmds']: + print('{}'.format(cmd['cmd'])) -def preconf(data): + def postfini(): print('\n#####################') - print('# PRE-CONF COMMANDS #') + print('# POST-FINI COMMANDS #') print('#####################') - if 'preconf' in data: - for node in data['preconf']: - for cmd in node['cmds']: - print('{}'.format(cmd['cmd'])) + if 'postfini' in appinfo.data: + for node in appinfo.data['postfini']: + for cmd in node['cmds']: + print('{}'.format(cmd['cmd'])) + + generate_mount_docker_netns() + generate_detach_physif_from_docker() + + print('\n################') + print('# FINI Commands #') + print('################') + if 'nodes' in appinfo.data: + for node in appinfo.data['nodes']: + for i in range(len(node['interfaces'])): + iface = node['interfaces'][i] + if (iface['type']=='phys'): + print('detach_physif_from_docker {} {}'.format(node['name'], iface['name'])) + for node in appinfo.data['nodes']: + nodetype = node.get('type', 'docker') + if nodetype=='docker': + print('docker stop {}'.format(node['name'])) + elif nodetype=='netns': + print('ip netns del {}'.format(node['name'])) + else: + print('unknown nodetype {}'.format(nodetype)) + sys.exit(1) + if 'switches' in appinfo.data: + for sw in appinfo.data['switches']: + print('ovs-vsctl del-br {}'.format(sw['name'])); + postfini() + +def command_pull(args): + print('{}()'.format(sys._getframe().f_code.co_name)) + print('\n######################') + print('# PULL DOCKER IMAGES #') + print('######################') + if 'nodes' in appinfo.data: + for node in appinfo.data['nodes']: + if node['type'] == 'docker': + print('docker pull {}'.format(node['image'])) + +def command_exec(args): + node = None + for n in appinfo.data['nodes']: + if n['name'] == args.NODE: + node = n + break + if node == None: + sys.stderr.write('no such node...\n') + sys.exit(1) + cmdstr = '' + node_type = node.get('type', 'docker') + if node_type == 'docker': + cmdstr = 'docker exec -it {}'.format(args.NODE) + elif node_type == 'netns': + cmdstr = 'ip netns exec {}'.format(args.NODE) + else: + sys.stderr.write('no such node type...\n') + sys.exit(1) + for s in args.COMMAND: + cmdstr = '{} {}'.format(cmdstr, s) + print('{}'.format(cmdstr)) -def init(data): +def command_build(args): + print('{}()'.format(sys._getframe().f_code.co_name)) + sys.stderr.write('ATODE\n') + sys.exit(1) + +def command_conf(args): + def preconf(data): print('\n#####################') - print('# INIT COMMANDS #') + print('# PRE-CONF COMMANDS #') print('#####################') + if 'preconf' in appinfo.data: + for node in appinfo.data['preconf']: + for cmd in node['cmds']: + print('{}'.format(cmd['cmd'])) - # CREATE NODES - print('\n# generate nodes') - if 'nodes' in data: - for node in data['nodes']: - nodetype = node.get('type', 'docker') - if nodetype == 'docker': - print('docker run -td --hostname {} ' - '--name {} --rm --privileged {}' - .format(node['name'], node['name'], - node['image'])) - elif nodetype == 'netns': - print('ip netns add {}'.format(node['name'])) - else: - print('unknown node-type {}'.format(node['type'])) - sys.exit(1) - - # CREATE SWITCHES - if 'switches' in data: - for sw in data['switches']: - print('ovs-vsctl add-br {} && ip link set {} up'.format(sw['name'], sw['name'])); - - links = [] - # CREATE Node to Node LINKS - class n2n_link: - left_node_name = None - left_iface_name = None - left_isset = False - left_node_type = None - right_node_name = None - right_iface_name = None - right_isset = False - right_node_type = None - def __init__(self, ln_name, ln_iface, rn_name=None, rn_iface=None): - self.left_node_name = ln_name - self.left_iface_name = ln_iface - self.right_node_name = rn_name - self.right_iface_name = rn_iface - self.left_isset = True - def koko(self): - # EXAMPLE: - # sudo ip link add net0 netns C0 type veth \ - # peer name net0 netns C1 - print('\n# connect {} to {}'.format(self.left_node_name, self.right_node_name)) - if self.left_node_type == 'docker': - print('mount_docker_netns {} {}'.format( - self.left_node_name, self.left_node_name)) - if self.right_node_type == 'docker': - print('mount_docker_netns {} {}'.format( - self.right_node_name, self.right_node_name)) - print('ip link add {} netns {} type veth peer name {} netns {}'.format( - self.left_iface_name, - self.left_node_name, - self.right_iface_name, - self.right_node_name)) - print('ip netns exec {} ip link set {} up'.format( - self.left_node_name, self.left_iface_name)) - print('ip netns exec {} ip link set {} up'.format( - self.right_node_name, self.right_iface_name)) - if self.left_node_type == 'docker': - print('ip netns del {}'.format(self.left_node_name)) - if self.right_node_type == 'docker': - print('ip netns del {}'.format(self.right_node_name)) - def check(self): - if not (self.right_isset and self.left_isset): - Exception('n2n_link state is not correct') - - if 'nodes' in data: - for node in data['nodes']: - for i in range(len(node['interfaces'])): - iface = node['interfaces'][i] - if (iface['type']=='direct'): - r_nname = iface['opts'].split('#')[0] - r_ifname = iface['opts'].split('#')[1] - peer_found = False - for link in links: - if link.right_isset == False: - b0 = link.left_node_name == r_nname - b1 = link.left_iface_name == r_ifname - if b0 and b1: # found peer - link.right_node_name = node['name'] - link.right_iface_name = iface['name'] - link.right_node_type = node.get('type', 'docker') - link.right_isset = True - peer_found = True - if peer_found == False: - new_link = n2n_link(node['name'], iface['name'], r_nname, r_ifname) - new_link.left_node_type = node.get('type', 'docker') - links.append(new_link) - for link in links: - link.check() - link.koko() - - links = [] - # CREATE Node to Switch LINKS - class s2n_link: - node_name = None - node_iface = None - node_isset = False - node_type = None - switch_name = None - switch_isset = False - def __init__(self, n_name, n_iface, n_type, s_name): - self.node_name = n_name - self.node_iface = n_iface - self.node_type = n_type - self.switch_name = s_name - - def koko(self): - if self.node_type == 'docker': - print('kokobr {} {} {}'.format(self.switch_name, self.node_name, self.node_iface)) - elif self.node_type == 'netns': - print('kokobr_netns {} {} {}'.format(self.switch_name, self.node_name, self.node_iface)) - else: - print('unknown node-type {}'.format(self.node_type)) - - def check(self): - if not (self.node_isset and self.switch_isset): - Exception('s2n_link state is not correct') - - if ('nodes' in data) and ('switches' in data): - for node in data['nodes']: - for i in range(len(node['interfaces'])): - iface = node['interfaces'][i] - if (iface['type']=='bridge'): - print('\n# connect {} and {}' - .format(node['name'], iface['opts'])) - new_link = s2n_link(node['name'], iface['name'], - node.get('type', 'docker'), iface['opts']) - new_link.node_isset = True - new_link.switch_isset = False - links.append(new_link) - for sw in data['switches']: - for i in range(len(sw['interfaces'])): - iface = sw['interfaces'][i] - for link in links: - if link.switch_isset == False: - b0 = iface['opts'] == link.node_name - b1 = iface['name'] == link.node_iface - b2 = sw['name'] == link.switch_name - if b0 and b1 and b2: - link.switch_isset = True - for link in links: - link.check() - link.koko() - - # Attach PhysNetIf to Conitaner - if 'nodes' in data: - for node in data['nodes']: - for i in range(len(node['interfaces'])): - iface = node['interfaces'][i] - if (iface['type']=='phys'): - print('koko_physnet {} {}'.format(node['name'], iface['name'])) - - # Attach raw veth to Conitaner - if 'nodes' in data: - for node in data['nodes']: - for i in range(len(node['interfaces'])): - iface = node['interfaces'][i] - if (iface['type']=='veth'): - print('ip link add {} type veth peer name {}'.format( - iface['name'], iface['opts'])) - print('koko_physnet {} {}'.format(node['name'], iface['name'])) - print('ip link set {} up'.format(iface['opts'])) - -def fini(data): - print('\n################') - print('# FINI Commands #') - print('################') - if 'nodes' in data: - for node in data['nodes']: - for i in range(len(node['interfaces'])): - iface = node['interfaces'][i] - if (iface['type']=='phys'): - print('detach_physif_from_docker {} {}'.format(node['name'], iface['name'])) - for node in data['nodes']: - nodetype = node.get('type', 'docker') - if nodetype=='docker': - print('docker stop {}'.format(node['name'])) - elif nodetype=='netns': - print('ip netns del {}'.format(node['name'])) - else: - print('unknown nodetype {}'.format(nodetype)) - sys.exit(1) - if 'switches' in data: - for sw in data['switches']: - print('ovs-vsctl del-br {}'.format(sw['name'])); - -def postfini(data): + def postconf(data): print('\n#####################') - print('# POST-FINI COMMANDS #') + print('# POST-CONF COMMANDS #') print('#####################') - if 'postfini' in data: - for node in data['postfini']: - for cmd in node['cmds']: - print('{}'.format(cmd['cmd'])) - -def get_node_type_from_nodes(data, name, default): - if 'nodes' in data: - for node in data['nodes']: - if node['name'] == name: - return node.get('type', default) + if 'postconf' in appinfo.data: + for node in appinfo.data['postconf']: + for cmd in node['cmds']: + print('{}'.format(cmd['cmd'])) + + def get_node_type_from_nodes(name, default): + if 'nodes' in appinfo.data: + for node in appinfo.data['nodes']: + if node['name'] == name: + return node.get('type', default) print('not found node {}'.format(name)) sys.exit(1) -def config(data): - print('\n################') - print('# NODE CONFIG #') - print('################') - if 'node_configs' in data: - for node in data['node_configs']: - print('echo {}::[config]::start'.format(node['name'])) - nodetype = get_node_type_from_nodes(data, node['name'], 'docker') - for cmd in node['cmds']: - if nodetype=='docker': - print('docker exec {} {}'.format(node['name'], cmd['cmd'])) - elif nodetype=='netns': - print('ip netns exec {} {}'.format(node['name'], cmd['cmd'])) - else: - print('unknown node-type {}'.format(nodetype)) - print('echo {}::[config]::fin'.format(node['name'])) - -def pull(data): - print('\n######################') - print('# PULL DOCKER IMAGES #') - print('######################') - if 'nodes' in data: - for node in data['nodes']: - print('docker pull {}'.format(node['image'])) - -def is_exist(graph, me): + preconf(appinfo.data) + print('\n################') + print('# NODE CONFIG #') + print('################') + if 'node_configs' in appinfo.data: + for node in appinfo.data['node_configs']: + print('echo {}::[config]::start'.format(node['name'])) + nodetype = get_node_type_from_nodes(node['name'], 'docker') + for cmd in node['cmds']: + if nodetype=='docker': + print('docker exec {} {}'.format(node['name'], cmd['cmd'])) + elif nodetype=='netns': + print('ip netns exec {} {}'.format(node['name'], cmd['cmd'])) + else: + print('unknown node-type {}'.format(nodetype)) + print('echo {}::[config]::fin'.format(node['name'])) + postconf(appinfo.data) + +def command_reconf(args): + command_reup(args) + command_conf(args) + +def command_reup(args): + command_down(args) + command_up(args) + +def command_version(args): + print(appinfo.version) + +def command_test(args): + print('\n#####################') + print('# INTEGRATION TEST #') + print('#####################') + if 'test' in appinfo.data: + print('set -eu') + for node in appinfo.data['test']: + for cmd in node['cmds']: + cmd_str = cmd['cmd'] + print('echo -n execute [{}]...'.format(cmd_str)) + print('{} >> /dev/null'.format(cmd_str)) + print('echo done') + print('echo') + +def command_init(args): + print(template_spec) + +def command_img(args): + def is_exist(graph, me): edge_list = graph.get_edge_list() for edge in edge_list: - pair = edge.obj_dict['points'] - me_pair = me.obj_dict['points'] - b0 = (pair[0]==me_pair[0] and pair[1]==me_pair[1]) - b1 = (pair[1]==me_pair[0] and pair[0]==me_pair[1]) - if (b0 or b1): - return True + pair = edge.obj_dict['points'] + me_pair = me.obj_dict['points'] + b0 = (pair[0]==me_pair[0] and pair[1]==me_pair[1]) + b1 = (pair[1]==me_pair[0] and pair[0]==me_pair[1]) + if (b0 or b1): + return True return False -def img(data, imgfile): - graph = pydot.Dot(graph_type='graph', overlap=False, splines=True) - for i in range(len(data['nodes'])): - node_name = data["nodes"][i]["name"] - graph.add_node(pydot.Node(node_name, label=node_name)) - iface_info = data["nodes"][i]["interfaces"] - for j in range(len(iface_info)): - opts_name = iface_info[j]['opts'].split("#")[0] - new_edge = pydot.Edge(node_name, opts_name) - new_edge = pydot.Edge(node_name, opts_name) - iface_name_label = iface_info[j]['name'] - new_edge.set_headlabel(iface_info[j]['opts'].split("#")[1]) - new_edge.set_taillabel(iface_info[j]['name']) - new_edge.set_fontsize(8) - if not is_exist(graph, new_edge): - graph.add_edge(new_edge) - graph.write_png(imgfile, prog='sfdp') - -def test(data): - print('\n#####################') - print('# INTEGRATION TEST #') - print('#####################') - if 'test' in data: - print('set -eu') - for node in data['test']: - for cmd in node['cmds']: - cmd_str = cmd['cmd'] - print('echo -n execute [{}]...'.format(cmd_str)) - print('{} >> /dev/null'.format(cmd_str)) - print('echo done') - print('echo') + graph = pydot.Dot(graph_type='graph', overlap=False, splines=True) + for i in range(len(appinfo.data['nodes'])): + node_name = appinfo.data["nodes"][i]["name"] + graph.add_node(pydot.Node(node_name, label=node_name)) + iface_info = appinfo.data["nodes"][i]["interfaces"] + for j in range(len(iface_info)): + args_name = iface_info[j]['args'].split("#")[0] + new_edge = pydot.Edge(node_name, args_name) + new_edge = pydot.Edge(node_name, args_name) + iface_name_label = iface_info[j]['name'] + new_edge.set_headlabel(iface_info[j]['args'].split("#")[1]) + new_edge.set_taillabel(iface_info[j]['name']) + new_edge.set_fontsize(8) + if not is_exist(graph, new_edge): + graph.add_edge(new_edge) + graph.write_png('topo.png', prog='sfdp') def main(): - - parser = argparse.ArgumentParser( - formatter_class=argparse.RawTextHelpFormatter) - parser.add_argument('option', - choices=['func', 'init', 'fini', 'reset', 'conf', 'test', 'reconf', 'tpl', 'pull', 'img'], - help='func just generate helper funcs \n' - 'init generate setup script \n' - 'fini generate destroy script \n' - 'test generate test script \n' - 'conf generate configuration script \n' - 'reset generate destroy and setup script \n' - 'reconf generate destroy, setup and config script \n' - 'tpl generate template yaml file \n' - 'pull generate docker image pulling script \n' - 'img generate network topology png file\n' - ) - parser.add_argument('-f', '--specfile', default='spec.yaml') - parser.add_argument('-v', '--imgfile', default='topo.png') - args = parser.parse_args() - specfile = args.specfile - imgfile = args.imgfile - option = args.option - - - if (option == 'func'): - generate_mount_docker_netns() - generate_kokobr() - generate_kokobr_netns() - generate_koko_physnet() - elif (option == 'init'): - data = yaml.load(open(specfile, "r+")) - generate_mount_docker_netns() - generate_kokobr() - generate_kokobr_netns() - generate_koko_physnet() - preinit(data) - init(data) - postinit(data) - elif (option == 'fini'): - generate_mount_docker_netns() - generate_detach_physif_from_docker() - data = yaml.load(open(specfile, "r+")) - fini(data) - postfini(data) - elif (option == 'reset'): - generate_mount_docker_netns() - generate_detach_physif_from_docker() - data = yaml.load(open(specfile, "r+")) - fini(data) - postfini(data) - generate_mount_docker_netns() - generate_kokobr() - generate_kokobr_netns() - generate_koko_physnet() - preinit(data) - init(data) - postinit(data) - elif (option == 'reconf'): - generate_mount_docker_netns() - generate_detach_physif_from_docker() - data = yaml.load(open(specfile, "r+")) - fini(data) - postfini(data) - generate_mount_docker_netns() - generate_kokobr() - generate_kokobr_netns() - generate_koko_physnet() - preinit(data) - init(data) - postinit(data) - preconf(data) - config(data) - elif (option == 'conf'): - data = yaml.load(open(specfile, "r+")) - preconf(data) - config(data) - elif (option == 'pull'): - data = yaml.load(open(specfile, "r+")) - pull(data) - elif (option == 'test'): - data = yaml.load(open(specfile, "r+")) - test(data) - elif (option == 'tpl'): - print('# http://www.asciiflow.com') - tpl() - elif (option == 'img'): - data = yaml.load(open(specfile, "r+")) - img(data, imgfile) - else: - parser.print_help() + parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter) + parser.add_argument('-f', '--specfile', default='spec.yaml') + parser.add_argument('-H', '--host', default=None) + parser.add_argument('--project-name', default='') + parser.add_argument('--verbose', action='store_true') + parser.add_argument('--dry-run', action='store_true') + # usage_text=''' + # tn [-f ...] [options] [COMMAND] [ARGS...] + # tn -h|--help + # + # Options: + # -f --specfile NAME Specify specification yaml file + # -v, --verbose Generate verbose shell + # --dry-run Print the recipes that are needed to execute the + # targets up to date, but not actually execute them. + # --project-name NAME Specify an alternate project name + # (default: none) + # --host HOST Daemon socket to connect to + # img Generate topology png file + # ''' + + subparsers = parser.add_subparsers(dest='command') + subparsers.required = True + + parser_ps = subparsers.add_parser('ps', + help='List services') + parser_ps.set_defaults(func=command_ps) + + parser_up = subparsers.add_parser('up', + help='Create and start containers') + parser_up.set_defaults(func=command_up) + + parser_down = subparsers.add_parser('down', + help='Stop and remove containers') + parser_down.set_defaults(func=command_down) + + parser_pull = subparsers.add_parser('pull', + help='Pull service images') + parser_pull.set_defaults(func=command_pull) + + parser_exec = subparsers.add_parser('exec', + help='Execute a command in a running container') + parser_exec.add_argument('NODE') + parser_exec.add_argument('COMMAND', nargs='+') + parser_exec.set_defaults(func=command_exec) + + parser_build = subparsers.add_parser('build', + help='Generate a Docker bundle from the spec file') + parser_build.set_defaults(func=command_build) + + parser_conf = subparsers.add_parser('conf', + help='Execute config-cmd in a running container') + parser_conf.set_defaults(func=command_conf) + + parser_reconf = subparsers.add_parser('reconf', + help='Stop, remove, create, start and config') + parser_reconf.set_defaults(func=command_reconf) + + parser_reup = subparsers.add_parser('reup', + help='Stop, remove, create and start') + parser_reup.set_defaults(func=command_reup) + + parser_version = subparsers.add_parser('version', + help='Show the tinet version information') + parser_version.set_defaults(func=command_version) + + parser_test = subparsers.add_parser('test', + help='Execute tests') + parser_test.set_defaults(func=command_test) + + parser_init = subparsers.add_parser('init', + help='Generate template spec file') + parser_init.set_defaults(func=command_init) + + parser_img = subparsers.add_parser('img', + help='Generate topology png file') + parser_img.set_defaults(func=command_img) + + args = parser.parse_args() + + # print('------------') + # print('verbose {}'.format(args.verbose)) + # print('specfile {}'.format(args.specfile)) + # print('host {}'.format(args.host)) + # print('pjname {}'.format(args.project_name)) + # print('command {}'.format(args.command)) + # print('------------') + + appinfo.verbose=args.verbose + appinfo.specfile=args.specfile + appinfo.host=args.host + appinfo.name=args.project_name + appinfo.command=args.command + + need_data = {'ps', 'up', 'down', 'pull', 'exec', + 'build', 'conf', 'reconf', 'reup', 'test', 'img'} + if args.command in need_data: + try: + filename = appinfo.specfile + appinfo.data = yaml.load(open(filename, "r+")) + except: + sys.stderr.write('{} not found.\n'.format(appinfo.specfile)) + sys.exit(1) + args.func(args) main() diff --git a/bin/tn.org b/bin/tn.org new file mode 100755 index 0000000..f4eabb6 --- /dev/null +++ b/bin/tn.org @@ -0,0 +1,506 @@ +#!/usr/bin/env python3 + +import sys +import yaml +import pprint +import argparse +import pydot + +def generate_mount_docker_netns(): + p = print + p('mount_docker_netns () { ') + p(' if [ $# -ne 2 ]; then ') + p(' echo "Usage: $0 " ') + p(' exit 1 ') + p(' fi ') + p(' mkdir -p /var/run/netns ') + p(' PID=`docker inspect $1 -f "{{.State.Pid}}"` ') + p(' ln -s /proc/$PID/ns/net /var/run/netns/$2 ') + p('} ') + +def generate_kokobr(): + p = print + p('kokobr () { ') + p(' if [ $# -ne 3 ]; then ') + p(' echo "Usage: $0 " ') + p(' exit 1 ') + p(' fi ') + p(' mount_docker_netns $2 $2 ') + p(' ip link add name $3 type veth peer name $2$3') + p(' ip link set dev $3 netns $2 ') + p(' ip link set $2$3 up ') + p(' ip netns exec $2 ip link set $3 up ') + p(' ip netns del $2 ') + p(' ovs-vsctl add-port $1 $2$3 ') + p('} ') + +def generate_kokobr_netns(): + p = print + p('kokobr_netns () { ') + p(' if [ $# -ne 3 ]; then ') + p(' echo "Usage: $0 " ') + p(' exit 1 ') + p(' fi ') + p(' ip link add name $3 type veth peer name $2$3') + p(' ip link set dev $3 netns $2 ') + p(' ip link set $2$3 up ') + p(' ip netns exec $2 ip link set $3 up ') + p(' ovs-vsctl add-port $1 $2$3 ') + p('} ') + +def generate_koko_physnet(): + p = print + p('koko_physnet () { ') + p(' if [ $# -ne 2 ]; then ') + p(' echo "Usage: $0 "') + p(' exit 1 ') + p(' fi ') + p(' mount_docker_netns $1 $1 ') + p(' ip link set dev $2 netns $1 ') + p(' ip netns exec $1 ip link set $2 up ') + p(' ip netns del $1 ') + p('} ') + +def generate_detach_physif_from_docker(): + p = print + p('detach_physif_from_docker () { ') + p(' if [ $# -ne 2 ]; then ') + p(' echo "Usage: $0 "') + p(' exit 1 ') + p(' fi ') + p(' mount_docker_netns $1 $1 ') + p(' ip netns exec $1 ip link set $2 netns 1') + p(' ip netns del $1 ') + p('} ') + +def tpl(): + p = print + p('nodes: ') + p(' - name: C0 ') + p(' image: slankdev/ubuntu:16.04 ') + p(' interfaces: ') + p(' - { name: net0, type: direct, args: C1#net0 }') + p(' - name: C0 ') + p(' image: slankdev/ubuntu:16.04 ') + p(' interfaces: ') + p(' - { name: net0, type: direct, args: C0#net0 }') + p(' ') + p('switches: ') + p(' - name: B0 ') + p(' interfaces: ') + p(' - { name: net0, type: container, args: C0 } ') + p(' ') + p('node_configs: ') + p(' - name: C0 ') + p(' cmds: ') + p(' - cmd: ip link set dev net0 up ') + p(' - cmd: >- ') + p(' vtysh -c "conf t" ') + p(' -c "router bgp 100 " ') + p(' -c " bgp router-id 2.2.2.2 " ') + p(' ') + p(' - name: C0 ') + p(' cmds: ') + p(' - cmd: echo slankdev slankdev ') + p('test: ') + p(' - cmds: ') + p(' - cmd: docker exec C0 ping -c2 10.0.0.2 ') + + +def preinit(data): + print('\n#####################') + print('# PRE-INIT COMMANDS #') + print('#####################') + if 'preinit' in data: + for node in data['preinit']: + for cmd in node['cmds']: + print('{}'.format(cmd['cmd'])) + +def postinit(data): + print('\n#####################') + print('# POST-INIT COMMANDS #') + print('#####################') + if 'postinit' in data: + for node in data['postinit']: + for cmd in node['cmds']: + print('{}'.format(cmd['cmd'])) + +def preconf(data): + print('\n#####################') + print('# PRE-CONF COMMANDS #') + print('#####################') + if 'preconf' in data: + for node in data['preconf']: + for cmd in node['cmds']: + print('{}'.format(cmd['cmd'])) + +def init(data): + print('\n#####################') + print('# INIT COMMANDS #') + print('#####################') + + # CREATE NODES + print('\n# generate nodes') + if 'nodes' in data: + for node in data['nodes']: + nodetype = node.get('type', 'docker') + if nodetype == 'docker': + print('docker run -td --hostname {} ' + '--name {} --rm --privileged {}' + .format(node['name'], node['name'], + node['image'])) + elif nodetype == 'netns': + print('ip netns add {}'.format(node['name'])) + else: + print('unknown node-type {}'.format(node['type'])) + sys.exit(1) + + # CREATE SWITCHES + if 'switches' in data: + for sw in data['switches']: + print('ovs-vsctl add-br {} && ip link set {} up'.format(sw['name'], sw['name'])); + + links = [] + # CREATE Node to Node LINKS + class n2n_link: + left_node_name = None + left_iface_name = None + left_isset = False + left_node_type = None + right_node_name = None + right_iface_name = None + right_isset = False + right_node_type = None + def __init__(self, ln_name, ln_iface, rn_name=None, rn_iface=None): + self.left_node_name = ln_name + self.left_iface_name = ln_iface + self.right_node_name = rn_name + self.right_iface_name = rn_iface + self.left_isset = True + def koko(self): + # EXAMPLE: + # sudo ip link add net0 netns C0 type veth \ + # peer name net0 netns C1 + print('\n# connect {} to {}'.format(self.left_node_name, self.right_node_name)) + if self.left_node_type == 'docker': + print('mount_docker_netns {} {}'.format( + self.left_node_name, self.left_node_name)) + if self.right_node_type == 'docker': + print('mount_docker_netns {} {}'.format( + self.right_node_name, self.right_node_name)) + print('ip link add {} netns {} type veth peer name {} netns {}'.format( + self.left_iface_name, + self.left_node_name, + self.right_iface_name, + self.right_node_name)) + print('ip netns exec {} ip link set {} up'.format( + self.left_node_name, self.left_iface_name)) + print('ip netns exec {} ip link set {} up'.format( + self.right_node_name, self.right_iface_name)) + if self.left_node_type == 'docker': + print('ip netns del {}'.format(self.left_node_name)) + if self.right_node_type == 'docker': + print('ip netns del {}'.format(self.right_node_name)) + def check(self): + if not (self.right_isset and self.left_isset): + Exception('n2n_link state is not correct') + + if 'nodes' in data: + for node in data['nodes']: + for i in range(len(node['interfaces'])): + iface = node['interfaces'][i] + if (iface['type']=='direct'): + r_nname = iface['args'].split('#')[0] + r_ifname = iface['args'].split('#')[1] + peer_found = False + for link in links: + if link.right_isset == False: + b0 = link.left_node_name == r_nname + b1 = link.left_iface_name == r_ifname + if b0 and b1: # found peer + link.right_node_name = node['name'] + link.right_iface_name = iface['name'] + link.right_node_type = node.get('type', 'docker') + link.right_isset = True + peer_found = True + if peer_found == False: + new_link = n2n_link(node['name'], iface['name'], r_nname, r_ifname) + new_link.left_node_type = node.get('type', 'docker') + links.append(new_link) + for link in links: + link.check() + link.koko() + + links = [] + # CREATE Node to Switch LINKS + class s2n_link: + node_name = None + node_iface = None + node_isset = False + node_type = None + switch_name = None + switch_isset = False + def __init__(self, n_name, n_iface, n_type, s_name): + self.node_name = n_name + self.node_iface = n_iface + self.node_type = n_type + self.switch_name = s_name + + def koko(self): + if self.node_type == 'docker': + print('kokobr {} {} {}'.format(self.switch_name, self.node_name, self.node_iface)) + elif self.node_type == 'netns': + print('kokobr_netns {} {} {}'.format(self.switch_name, self.node_name, self.node_iface)) + else: + print('unknown node-type {}'.format(self.node_type)) + + def check(self): + if not (self.node_isset and self.switch_isset): + Exception('s2n_link state is not correct') + + if ('nodes' in data) and ('switches' in data): + for node in data['nodes']: + for i in range(len(node['interfaces'])): + iface = node['interfaces'][i] + if (iface['type']=='bridge'): + print('\n# connect {} and {}' + .format(node['name'], iface['args'])) + new_link = s2n_link(node['name'], iface['name'], + node.get('type', 'docker'), iface['args']) + new_link.node_isset = True + new_link.switch_isset = False + links.append(new_link) + for sw in data['switches']: + for i in range(len(sw['interfaces'])): + iface = sw['interfaces'][i] + for link in links: + if link.switch_isset == False: + b0 = iface['args'] == link.node_name + b1 = iface['name'] == link.node_iface + b2 = sw['name'] == link.switch_name + if b0 and b1 and b2: + link.switch_isset = True + for link in links: + link.check() + link.koko() + + # Attach PhysNetIf to Conitaner + if 'nodes' in data: + for node in data['nodes']: + for i in range(len(node['interfaces'])): + iface = node['interfaces'][i] + if (iface['type']=='phys'): + print('koko_physnet {} {}'.format(node['name'], iface['name'])) + + # Attach raw veth to Conitaner + if 'nodes' in data: + for node in data['nodes']: + for i in range(len(node['interfaces'])): + iface = node['interfaces'][i] + if (iface['type']=='veth'): + print('ip link add {} type veth peer name {}'.format( + iface['name'], iface['args'])) + print('koko_physnet {} {}'.format(node['name'], iface['name'])) + print('ip link set {} up'.format(iface['args'])) + +def fini(data): + print('\n################') + print('# FINI Commands #') + print('################') + if 'nodes' in data: + for node in data['nodes']: + for i in range(len(node['interfaces'])): + iface = node['interfaces'][i] + if (iface['type']=='phys'): + print('detach_physif_from_docker {} {}'.format(node['name'], iface['name'])) + for node in data['nodes']: + nodetype = node.get('type', 'docker') + if nodetype=='docker': + print('docker stop {}'.format(node['name'])) + elif nodetype=='netns': + print('ip netns del {}'.format(node['name'])) + else: + print('unknown nodetype {}'.format(nodetype)) + sys.exit(1) + if 'switches' in data: + for sw in data['switches']: + print('ovs-vsctl del-br {}'.format(sw['name'])); + +def postfini(data): + print('\n#####################') + print('# POST-FINI COMMANDS #') + print('#####################') + if 'postfini' in data: + for node in data['postfini']: + for cmd in node['cmds']: + print('{}'.format(cmd['cmd'])) + +def get_node_type_from_nodes(data, name, default): + if 'nodes' in data: + for node in data['nodes']: + if node['name'] == name: + return node.get('type', default) + print('not found node {}'.format(name)) + sys.exit(1) + +def config(data): + print('\n################') + print('# NODE CONFIG #') + print('################') + if 'node_configs' in data: + for node in data['node_configs']: + print('echo {}::[config]::start'.format(node['name'])) + nodetype = get_node_type_from_nodes(data, node['name'], 'docker') + for cmd in node['cmds']: + if nodetype=='docker': + print('docker exec {} {}'.format(node['name'], cmd['cmd'])) + elif nodetype=='netns': + print('ip netns exec {} {}'.format(node['name'], cmd['cmd'])) + else: + print('unknown node-type {}'.format(nodetype)) + print('echo {}::[config]::fin'.format(node['name'])) + +def pull(data): + print('\n######################') + print('# PULL DOCKER IMAGES #') + print('######################') + if 'nodes' in data: + for node in data['nodes']: + print('docker pull {}'.format(node['image'])) + +def is_exist(graph, me): + edge_list = graph.get_edge_list() + for edge in edge_list: + pair = edge.obj_dict['points'] + me_pair = me.obj_dict['points'] + b0 = (pair[0]==me_pair[0] and pair[1]==me_pair[1]) + b1 = (pair[1]==me_pair[0] and pair[0]==me_pair[1]) + if (b0 or b1): + return True + return False + +def img(data, imgfile): + graph = pydot.Dot(graph_type='graph', overlap=False, splines=True) + for i in range(len(data['nodes'])): + node_name = data["nodes"][i]["name"] + graph.add_node(pydot.Node(node_name, label=node_name)) + iface_info = data["nodes"][i]["interfaces"] + for j in range(len(iface_info)): + args_name = iface_info[j]['args'].split("#")[0] + new_edge = pydot.Edge(node_name, args_name) + new_edge = pydot.Edge(node_name, args_name) + iface_name_label = iface_info[j]['name'] + new_edge.set_headlabel(iface_info[j]['args'].split("#")[1]) + new_edge.set_taillabel(iface_info[j]['name']) + new_edge.set_fontsize(8) + if not is_exist(graph, new_edge): + graph.add_edge(new_edge) + graph.write_png(imgfile, prog='sfdp') + +def test(data): + print('\n#####################') + print('# INTEGRATION TEST #') + print('#####################') + if 'test' in data: + print('set -eu') + for node in data['test']: + for cmd in node['cmds']: + cmd_str = cmd['cmd'] + print('echo -n execute [{}]...'.format(cmd_str)) + print('{} >> /dev/null'.format(cmd_str)) + print('echo done') + print('echo') + +def main(): + + parser = argparse.ArgumentParser( + formatter_class=argparse.RawTextHelpFormatter) + parser.add_argument('option', + choices=['func', 'init', 'fini', 'reset', 'conf', 'test', 'reconf', 'tpl', 'pull', 'img'], + help='func just generate helper funcs \n' + 'init generate setup script \n' + 'fini generate destroy script \n' + 'test generate test script \n' + 'conf generate configuration script \n' + 'reset generate destroy and setup script \n' + 'reconf generate destroy, setup and config script \n' + 'tpl generate template yaml file \n' + 'pull generate docker image pulling script \n' + 'img generate network topology png file\n' + ) + parser.add_argument('-f', '--specfile', default='spec.yaml') + parser.add_argument('-v', '--imgfile', default='topo.png') + args = parser.parse_args() + specfile = args.specfile + imgfile = args.imgfile + option = args.option + + + if (option == 'func'): + generate_mount_docker_netns() + generate_kokobr() + generate_kokobr_netns() + generate_koko_physnet() + elif (option == 'init'): + data = yaml.load(open(specfile, "r+")) + generate_mount_docker_netns() + generate_kokobr() + generate_kokobr_netns() + generate_koko_physnet() + preinit(data) + init(data) + postinit(data) + elif (option == 'fini'): + generate_mount_docker_netns() + generate_detach_physif_from_docker() + data = yaml.load(open(specfile, "r+")) + fini(data) + postfini(data) + elif (option == 'reset'): + generate_mount_docker_netns() + generate_detach_physif_from_docker() + data = yaml.load(open(specfile, "r+")) + fini(data) + postfini(data) + generate_mount_docker_netns() + generate_kokobr() + generate_kokobr_netns() + generate_koko_physnet() + preinit(data) + init(data) + postinit(data) + elif (option == 'reconf'): + generate_mount_docker_netns() + generate_detach_physif_from_docker() + data = yaml.load(open(specfile, "r+")) + fini(data) + postfini(data) + generate_mount_docker_netns() + generate_kokobr() + generate_kokobr_netns() + generate_koko_physnet() + preinit(data) + init(data) + postinit(data) + preconf(data) + config(data) + elif (option == 'conf'): + data = yaml.load(open(specfile, "r+")) + preconf(data) + config(data) + elif (option == 'pull'): + data = yaml.load(open(specfile, "r+")) + pull(data) + elif (option == 'test'): + data = yaml.load(open(specfile, "r+")) + test(data) + elif (option == 'tpl'): + print('# http://www.asciiflow.com') + tpl() + elif (option == 'img'): + data = yaml.load(open(specfile, "r+")) + img(data, imgfile) + else: + parser.print_help() + +main() diff --git a/docs/specification_yml.md b/docs/specification_yml.md index e992cb6..f36b540 100644 --- a/docs/specification_yml.md +++ b/docs/specification_yml.md @@ -2,27 +2,27 @@ # Yaml Format -## Service Definition +## Node Definition ``` -services: +nodes: - name: Node0 image: ubuntu:18.04 interfaces: - - { name: net0, type: direct, opts: R0#net1 } + - { name: net0, type: direct, args: R0#net1 } ``` ### Node type -- name: service name. It will be container-name or netns-name. -- type: service type (default: docker) - - docker: service is docker container - - netns: service is just network namespace +- name: node name. It will be container-name or netns-name. +- type: node type (default: docker) + - docker: node is docker container + - netns: node is just network namespace - image: specify docker-image - build: specify Dockerfile's path ``` -services: +nodes: - name: Node0 image: ubuntu:18.04 - name: Node1 @@ -36,11 +36,11 @@ services: - type - direct: p2p connect to other container - bridge: bridge connection - - phys : host's network interface + - phys : host's network interface - mac: specify mac address ``` -services: +nodes: - name: Node0 image: ubuntu:18.04 interfaces: @@ -52,8 +52,8 @@ services: ### Bridge Definition -If you use the bridge interface type, you need to -define the Bridge-Instance. It'll be created as a +If you use the bridge interface type, you need to +define the Bridge-Instance. It'll be created as a OvS-instance. - name: interface name diff --git a/examples/WIP_shownet2018/spec2.yaml b/examples/WIP_shownet2018/spec2.yaml index aaadf04..4bbadc3 100644 --- a/examples/WIP_shownet2018/spec2.yaml +++ b/examples/WIP_shownet2018/spec2.yaml @@ -10,161 +10,161 @@ nodes: interfaces: - name: net0 type: direct - opts: R6#net1 + args: R6#net1 - name: net1 type: direct - opts: R1#net1 + args: R1#net1 - name: net2 type: direct - opts: R3#net1 + args: R3#net1 - name: net3 type: direct - opts: R2#net0 + args: R2#net0 - name: R1 image: slankdev/frr interfaces: - name: net0 type: direct - opts: R7#net1 + args: R7#net1 - name: net1 type: direct - opts: R0#net1 + args: R0#net1 - name: net2 type: direct - opts: R2#net1 + args: R2#net1 - name: net3 type: direct - opts: R3#net0 + args: R3#net0 - name: R2 image: slankdev/frr interfaces: - name: net0 type: direct - opts: R0#net3 + args: R0#net3 - name: net1 type: direct - opts: R1#net2 + args: R1#net2 - name: net2 type: direct - opts: R3#net2 + args: R3#net2 - name: net3 type: direct - opts: R4#net0 + args: R4#net0 - name: R3 image: slankdev/frr interfaces: - name: net0 type: direct - opts: R1#net3 + args: R1#net3 - name: net1 type: direct - opts: R0#net2 + args: R0#net2 - name: net2 type: direct - opts: R2#net2 + args: R2#net2 - name: net3 type: direct - opts: R5#net0 + args: R5#net0 - name: R4 image: slankdev/frr interfaces: - name: net0 type: direct - opts: R2#net3 + args: R2#net3 - name: net1 type: bridge - opts: B0 + args: B0 - name: R5 image: slankdev/frr interfaces: - name: net0 type: direct - opts: R3#net3 + args: R3#net3 - name: net1 type: bridge - opts: B1 + args: B1 - name: R6 image: slankdev/frr interfaces: - name: net0 type: direct - opts: S0#net0 + args: S0#net0 - name: net1 type: direct - opts: R0#net0 + args: R0#net0 - name: net2 type: direct - opts: R7#net2 + args: R7#net2 - name: R7 image: slankdev/frr interfaces: - name: net0 type: direct - opts: S1#net0 + args: S1#net0 - name: net1 type: direct - opts: R1#net0 + args: R1#net0 - name: net2 type: direct - opts: R6#net2 + args: R6#net2 - name: S0 image: slankdev/ubuntu:16.04 interfaces: - name: net0 type: direct - opts: R6#net0 + args: R6#net0 - name: S1 image: slankdev/ubuntu:16.04 interfaces: - name: net0 type: direct - opts: R7#net0 + args: R7#net0 - name: C0 image: slankdev/ubuntu:16.04 interfaces: - name: net0 type: bridge - opts: B0 + args: B0 - name: C1 image: slankdev/ubuntu:16.04 interfaces: - name: net0 type: bridge - opts: B0 + args: B0 - name: C2 image: slankdev/ubuntu:16.04 interfaces: - name: net0 type: bridge - opts: B1 + args: B1 - name: C3 image: slankdev/ubuntu:16.04 interfaces: - name: net0 type: bridge - opts: B1 + args: B1 switches: - name: B0 interfaces: - name: net3 type: container - opts: R2 + args: R2 - name: net0 type: container - opts: C0 + args: C0 - name: net0 type: container - opts: C1 + args: C1 - name: B1 interfaces: - name: net3 type: container - opts: R3 + args: R3 - name: net0 type: container - opts: C2 + args: C2 - name: net0 type: container - opts: C3 + args: C3 diff --git a/examples/basic_bfd/spec.yaml b/examples/basic_bfd/spec.yaml index addd6ce..518261c 100644 --- a/examples/basic_bfd/spec.yaml +++ b/examples/basic_bfd/spec.yaml @@ -4,23 +4,23 @@ nodes: - name: R1 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R2#net0 } - - { name: net1, type: direct, opts: R3#net0 } + - { name: net0, type: direct, args: R2#net0 } + - { name: net1, type: direct, args: R3#net0 } - name: R2 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R1#net0 } - - { name: net1, type: direct, opts: R4#net0 } + - { name: net0, type: direct, args: R1#net0 } + - { name: net1, type: direct, args: R4#net0 } - name: R3 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R1#net1 } - - { name: net1, type: direct, opts: R4#net1 } + - { name: net0, type: direct, args: R1#net1 } + - { name: net1, type: direct, args: R4#net1 } - name: R4 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R2#net1 } - - { name: net1, type: direct, opts: R3#net1 } + - { name: net0, type: direct, args: R2#net1 } + - { name: net1, type: direct, args: R3#net1 } node_configs: - name: R1 diff --git a/examples/basic_ebgp/spec.yaml b/examples/basic_ebgp/spec.yaml index 9da6dbe..5be971f 100644 --- a/examples/basic_ebgp/spec.yaml +++ b/examples/basic_ebgp/spec.yaml @@ -32,32 +32,32 @@ nodes: - name: R0 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R1#net0 } - - { name: net1, type: direct, opts: R2#net0 } + - { name: net0, type: direct, args: R1#net0 } + - { name: net1, type: direct, args: R2#net0 } - name: R1 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R0#net0 } - - { name: net1, type: direct, opts: R3#net0 } + - { name: net0, type: direct, args: R0#net0 } + - { name: net1, type: direct, args: R3#net0 } - name: R2 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R0#net1 } - - { name: net1, type: direct, opts: C0#net0 } + - { name: net0, type: direct, args: R0#net1 } + - { name: net1, type: direct, args: C0#net0 } - name: R3 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R1#net1 } - - { name: net1, type: direct, opts: C1#net0 } + - { name: net0, type: direct, args: R1#net1 } + - { name: net1, type: direct, args: C1#net0 } - name: C0 image: slankdev/ubuntu:16.04 interfaces: - - { name: net0, type: direct, opts: R2#net1 } + - { name: net0, type: direct, args: R2#net1 } - name: C1 image: slankdev/ubuntu:16.04 interfaces: - - { name: net0, type: direct, opts: R3#net1 } + - { name: net0, type: direct, args: R3#net1 } node_configs: - name: R0 diff --git a/examples/basic_ecmp/scale.diff b/examples/basic_ecmp/scale.diff index 3132286..a7a597f 100644 --- a/examples/basic_ecmp/scale.diff +++ b/examples/basic_ecmp/scale.diff @@ -4,26 +4,26 @@ index c2c0bd2..79ab538 100644 +++ b/examples/basic_ecmp/spec.yaml @@ -38,6 +38,16 @@ nodes: interfaces: - - { name: net0, type: direct, opts: R3#net1 } + - { name: net0, type: direct, args: R3#net1 } + - name: R4 + image: slankdev/frr + interfaces: -+ - { name: net0, type: bridge, opts: B0 } -+ - { name: net1, type: direct, opts: S4#net0 } ++ - { name: net0, type: bridge, args: B0 } ++ - { name: net1, type: direct, args: S4#net0 } + - name: S4 + image: tmp + interfaces: -+ - { name: net0, type: direct, opts: R4#net1 } ++ - { name: net0, type: direct, args: R4#net1 } + switches: - name: B0 interfaces: @@ -45,6 +55,7 @@ switches: - - { name: net0, type: container, opts: R1 } - - { name: net0, type: container, opts: R2 } - - { name: net0, type: container, opts: R3 } -+ - { name: net0, type: container, opts: R4 } + - { name: net0, type: container, args: R1 } + - { name: net0, type: container, args: R2 } + - { name: net0, type: container, args: R3 } ++ - { name: net0, type: container, args: R4 } node_configs: - name: S0 diff --git a/examples/basic_ecmp/spec.yaml b/examples/basic_ecmp/spec.yaml index bcf3ea7..df0c54c 100644 --- a/examples/basic_ecmp/spec.yaml +++ b/examples/basic_ecmp/spec.yaml @@ -4,47 +4,47 @@ nodes: - name: S0 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R0#net1 } + - { name: net0, type: direct, args: R0#net1 } - name: R0 image: slankdev/frr interfaces: - - { name: net1, type: direct, opts: S0#net0 } - - { name: net0, type: bridge, opts: B0 } + - { name: net1, type: direct, args: S0#net0 } + - { name: net0, type: bridge, args: B0 } - name: R1 image: slankdev/frr interfaces: - - { name: net0, type: bridge, opts: B0 } - - { name: net1, type: direct, opts: S1#net0 } + - { name: net0, type: bridge, args: B0 } + - { name: net1, type: direct, args: S1#net0 } - name: S1 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R1#net1 } + - { name: net0, type: direct, args: R1#net1 } - name: R2 image: slankdev/frr interfaces: - - { name: net0, type: bridge, opts: B0 } - - { name: net1, type: direct, opts: S2#net0 } + - { name: net0, type: bridge, args: B0 } + - { name: net1, type: direct, args: S2#net0 } - name: S2 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R2#net1 } + - { name: net0, type: direct, args: R2#net1 } - name: R3 image: slankdev/frr interfaces: - - { name: net0, type: bridge, opts: B0 } - - { name: net1, type: direct, opts: S3#net0 } + - { name: net0, type: bridge, args: B0 } + - { name: net1, type: direct, args: S3#net0 } - name: S3 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R3#net1 } + - { name: net0, type: direct, args: R3#net1 } switches: - name: B0 interfaces: - - { name: net0, type: container, opts: R0 } - - { name: net0, type: container, opts: R1 } - - { name: net0, type: container, opts: R2 } - - { name: net0, type: container, opts: R3 } + - { name: net0, type: container, args: R0 } + - { name: net0, type: container, args: R1 } + - { name: net0, type: container, args: R2 } + - { name: net0, type: container, args: R3 } node_configs: - name: S0 diff --git a/examples/basic_evpn/spec.yaml b/examples/basic_evpn/spec.yaml index 1f2204d..30776ef 100644 --- a/examples/basic_evpn/spec.yaml +++ b/examples/basic_evpn/spec.yaml @@ -24,32 +24,32 @@ nodes: - name: RR0 image: slankdev/frr interfaces: - - { name: net0, type: bridge, opts: B0 } + - { name: net0, type: bridge, args: B0 } - name: R0 image: slankdev/frr interfaces: - - { name: net0, type: bridge, opts: B0 } - - { name: net1, type: direct, opts: C0#net0 } + - { name: net0, type: bridge, args: B0 } + - { name: net1, type: direct, args: C0#net0 } - name: R1 image: slankdev/frr interfaces: - - { name: net0, type: bridge, opts: B0 } - - { name: net1, type: direct, opts: C1#net0 } + - { name: net0, type: bridge, args: B0 } + - { name: net1, type: direct, args: C1#net0 } - name: C0 image: slankdev/ubuntu:16.04 interfaces: - - { name: net0, type: direct, opts: R0#net1 } + - { name: net0, type: direct, args: R0#net1 } - name: C1 image: slankdev/ubuntu:16.04 interfaces: - - { name: net0, type: direct, opts: R1#net1 } + - { name: net0, type: direct, args: R1#net1 } switches: - name: B0 interfaces: - - { name: net0, type: container, opts: R0 } - - { name: net0, type: container, opts: R1 } - - { name: net0, type: container, opts: RR0 } + - { name: net0, type: container, args: R0 } + - { name: net0, type: container, args: R1 } + - { name: net0, type: container, args: RR0 } node_configs: - name: RR0 diff --git a/examples/basic_ibgp_rr/spec.yaml b/examples/basic_ibgp_rr/spec.yaml index bba12fe..56ed305 100644 --- a/examples/basic_ibgp_rr/spec.yaml +++ b/examples/basic_ibgp_rr/spec.yaml @@ -27,45 +27,45 @@ nodes: - name: RR0 image: slankdev/frr interfaces: - - { name: net0, type: bridge, opts: B0 } + - { name: net0, type: bridge, args: B0 } - name: R0 image: slankdev/frr interfaces: - - { name: net0, type: bridge, opts: B0 } - - { name: net1, type: direct, opts: C0#net0 } + - { name: net0, type: bridge, args: B0 } + - { name: net1, type: direct, args: C0#net0 } - name: C0 image: slankdev/ubuntu:16.04 interfaces: - - { name: net0, type: direct, opts: R0#net1 } + - { name: net0, type: direct, args: R0#net1 } - name: R1 image: slankdev/frr interfaces: - - { name: net0, type: bridge, opts: B0 } - - { name: net1, type: direct, opts: C1#net0 } + - { name: net0, type: bridge, args: B0 } + - { name: net1, type: direct, args: C1#net0 } - name: C1 image: slankdev/ubuntu:16.04 interfaces: - - { name: net0, type: direct, opts: R1#net1 } + - { name: net0, type: direct, args: R1#net1 } - name: R2 image: slankdev/frr interfaces: - - { name: net0, type: bridge, opts: B0 } - - { name: net1, type: direct, opts: C2#net0 } + - { name: net0, type: bridge, args: B0 } + - { name: net1, type: direct, args: C2#net0 } - name: C2 image: slankdev/ubuntu:16.04 interfaces: - - { name: net0, type: direct, opts: R2#net1 } + - { name: net0, type: direct, args: R2#net1 } switches: - name: B0 interfaces: - - { name: net0, type: container, opts: RR0 } - - { name: net0, type: container, opts: R0 } - - { name: net0, type: container, opts: R1 } - - { name: net0, type: container, opts: R2 } + - { name: net0, type: container, args: RR0 } + - { name: net0, type: container, args: R0 } + - { name: net0, type: container, args: R1 } + - { name: net0, type: container, args: R2 } node_configs: - name: RR0 diff --git a/examples/basic_mpls/spec.yaml b/examples/basic_mpls/spec.yaml index 2f552ec..e96f042 100644 --- a/examples/basic_mpls/spec.yaml +++ b/examples/basic_mpls/spec.yaml @@ -44,43 +44,43 @@ nodes: - name: R0 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R2#net1 } - - { name: net1, type: direct, opts: C0#net0 } + - { name: net0, type: direct, args: R2#net1 } + - { name: net1, type: direct, args: C0#net0 } - name: R1 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R3#net1 } - - { name: net1, type: direct, opts: C1#net0 } + - { name: net0, type: direct, args: R3#net1 } + - { name: net1, type: direct, args: C1#net0 } - name: R2 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R5#net0 } - - { name: net1, type: direct, opts: R0#net0 } - - { name: net2, type: direct, opts: R4#net0 } + - { name: net0, type: direct, args: R5#net0 } + - { name: net1, type: direct, args: R0#net0 } + - { name: net2, type: direct, args: R4#net0 } - name: R3 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R5#net1 } - - { name: net1, type: direct, opts: R1#net0 } - - { name: net2, type: direct, opts: R4#net1 } + - { name: net0, type: direct, args: R5#net1 } + - { name: net1, type: direct, args: R1#net0 } + - { name: net2, type: direct, args: R4#net1 } - name: R4 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R2#net2 } - - { name: net1, type: direct, opts: R3#net2 } + - { name: net0, type: direct, args: R2#net2 } + - { name: net1, type: direct, args: R3#net2 } - name: R5 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R2#net0 } - - { name: net1, type: direct, opts: R3#net0 } + - { name: net0, type: direct, args: R2#net0 } + - { name: net1, type: direct, args: R3#net0 } - name: C0 image: slankdev/ubuntu:18.04 interfaces: - - { name: net0, type: direct, opts: R0#net1 } + - { name: net0, type: direct, args: R0#net1 } - name: C1 image: slankdev/ubuntu:18.04 interfaces: - - { name: net0, type: direct, opts: R1#net1 } + - { name: net0, type: direct, args: R1#net1 } node_configs: diff --git a/examples/basic_napt/spec.yaml b/examples/basic_napt/spec.yaml index 16fac9b..8e9a8bd 100644 --- a/examples/basic_napt/spec.yaml +++ b/examples/basic_napt/spec.yaml @@ -29,22 +29,22 @@ nodes: interfaces: - name: net0 type: direct - opts: S0#net0 + args: S0#net0 - name: net1 type: direct - opts: C0#net0 + args: C0#net0 - name: S0 image: slankdev/ubuntu:16.04 interfaces: - name: net0 type: direct - opts: R0#net0 + args: R0#net0 - name: C0 image: slankdev/ubuntu:16.04 interfaces: - name: net0 type: direct - opts: R0#net1 + args: R0#net1 node_configs: - name: R0 diff --git a/examples/basic_netns/spec.yaml b/examples/basic_netns/spec.yaml index abc303c..a97095f 100644 --- a/examples/basic_netns/spec.yaml +++ b/examples/basic_netns/spec.yaml @@ -3,16 +3,16 @@ nodes: - name: H0 type: netns interfaces: - - { name: net0, type: direct, opts: C0#net0 } - - { name: net1, type: direct, opts: C1#net0 } + - { name: net0, type: direct, args: C0#net0 } + - { name: net1, type: direct, args: C1#net0 } - name: C0 image: slankdev/ubuntu:18.04 interfaces: - - { name: net0, type: direct, opts: H0#net0 } + - { name: net0, type: direct, args: H0#net0 } - name: C1 image: slankdev/ubuntu:18.04 interfaces: - - { name: net0, type: direct, opts: H0#net1 } + - { name: net0, type: direct, args: H0#net1 } node_configs: - name: H0 diff --git a/examples/basic_ospf/spec.yaml b/examples/basic_ospf/spec.yaml index e1fa2c6..4c489a9 100644 --- a/examples/basic_ospf/spec.yaml +++ b/examples/basic_ospf/spec.yaml @@ -13,38 +13,38 @@ nodes: - name: R1 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R2#net0 } - - { name: net1, type: direct, opts: R3#net0 } - - { name: net2, type: direct, opts: S1#net0 } + - { name: net0, type: direct, args: R2#net0 } + - { name: net1, type: direct, args: R3#net0 } + - { name: net2, type: direct, args: S1#net0 } - name: R2 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R1#net0 } - - { name: net1, type: direct, opts: R4#net0 } + - { name: net0, type: direct, args: R1#net0 } + - { name: net1, type: direct, args: R4#net0 } - name: R3 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R1#net1 } - - { name: net1, type: direct, opts: R4#net1 } - - { name: net2, type: direct, opts: S3#net0 } + - { name: net0, type: direct, args: R1#net1 } + - { name: net1, type: direct, args: R4#net1 } + - { name: net2, type: direct, args: S3#net0 } - name: R4 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R2#net1 } - - { name: net1, type: direct, opts: R3#net1 } - - { name: net2, type: direct, opts: S4#net0 } + - { name: net0, type: direct, args: R2#net1 } + - { name: net1, type: direct, args: R3#net1 } + - { name: net2, type: direct, args: S4#net0 } - name: S1 image: slankdev/ubuntu:18.04 interfaces: - - { name: net0, type: direct, opts: R1#net2 } + - { name: net0, type: direct, args: R1#net2 } - name: S3 image: slankdev/ubuntu:18.04 interfaces: - - { name: net0, type: direct, opts: R3#net2 } + - { name: net0, type: direct, args: R3#net2 } - name: S4 image: slankdev/ubuntu:18.04 interfaces: - - { name: net0, type: direct, opts: R4#net2 } + - { name: net0, type: direct, args: R4#net2 } node_configs: - name: S1 diff --git a/examples/basic_pppoe_WIP/spec.yaml b/examples/basic_pppoe_WIP/spec.yaml index 1a1e3e1..b481e95 100644 --- a/examples/basic_pppoe_WIP/spec.yaml +++ b/examples/basic_pppoe_WIP/spec.yaml @@ -4,27 +4,27 @@ nodes: - name: R0 image: tmp interfaces: - - { name: net0, type: bridge, opts: B0 } - - { name: net1, type: direct, opts: S0#net0 } + - { name: net0, type: bridge, args: B0 } + - { name: net1, type: direct, args: S0#net0 } - name: S0 image: tmp interfaces: - - { name: net0, type: direct, opts: R0#net1 } + - { name: net0, type: direct, args: R0#net1 } - name: S1 image: tmp interfaces: - - { name: net0, type: bridge, opts: B0 } + - { name: net0, type: bridge, args: B0 } - name: S2 image: tmp interfaces: - - { name: net0, type: bridge, opts: B0 } + - { name: net0, type: bridge, args: B0 } switches: - name: B0 interfaces: - - { name: net0, type: container, opts: R0 } - - { name: net0, type: container, opts: S1 } - - { name: net0, type: container, opts: S2 } + - { name: net0, type: container, args: R0 } + - { name: net0, type: container, args: S1 } + - { name: net0, type: container, args: S2 } node_configs: - name: R0 diff --git a/examples/basic_srmpls/spec.yaml b/examples/basic_srmpls/spec.yaml index 574b56e..5ca4cb4 100644 --- a/examples/basic_srmpls/spec.yaml +++ b/examples/basic_srmpls/spec.yaml @@ -10,25 +10,25 @@ nodes: - name: R1 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R1#net0 } - - { name: net1, type: direct, opts: R4#net0 } + - { name: net0, type: direct, args: R1#net0 } + - { name: net1, type: direct, args: R4#net0 } - name: R2 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R1#net0 } - - { name: net1, type: direct, opts: R3#net0 } - - { name: net2, type: direct, opts: R4#net2 } + - { name: net0, type: direct, args: R1#net0 } + - { name: net1, type: direct, args: R3#net0 } + - { name: net2, type: direct, args: R4#net2 } - name: R3 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R2#net1 } - - { name: net1, type: direct, opts: R4#net1 } + - { name: net0, type: direct, args: R2#net1 } + - { name: net1, type: direct, args: R4#net1 } - name: R4 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R1#net1 } - - { name: net1, type: direct, opts: R3#net1 } - - { name: net2, type: direct, opts: R2#net2 } + - { name: net0, type: direct, args: R1#net1 } + - { name: net1, type: direct, args: R3#net1 } + - { name: net2, type: direct, args: R2#net2 } node_configs: - name: R1 diff --git a/examples/basic_srv6/spec.yaml b/examples/basic_srv6/spec.yaml index 3cf891b..5794b2f 100644 --- a/examples/basic_srv6/spec.yaml +++ b/examples/basic_srv6/spec.yaml @@ -5,46 +5,47 @@ nodes: - name: S0 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R0#net1 } + - { name: net0, type: direct, args: R0#net1 } - name: S1 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R2#net1 } + - { name: net0, type: direct, args: R2#net1 } - name: R0 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R1#net0 } - - { name: net1, type: direct, opts: S0#net0 } + - { name: net0, type: direct, args: R1#net0 } + - { name: net1, type: direct, args: S0#net0 } - name: R1 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R0#net0 } - - { name: net1, type: direct, opts: R2#net0 } - - { name: net2, type: bridge, opts: SW0 } + - { name: net0, type: direct, args: R0#net0 } + - { name: net1, type: direct, args: R2#net0 } + - { name: net2, type: bridge, args: SW0 } - name: R2 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R1#net1 } - - { name: net1, type: direct, opts: S1#net0 } + - { name: net0, type: direct, args: R1#net1 } + - { name: net1, type: direct, args: S1#net0 } - name: R3 image: slankdev/frr interfaces: - - { name: net0, type: bridge, opts: SW0 } + - { name: net0, type: bridge, args: SW0 } - name: R4 image: slankdev/frr interfaces: - - { name: net0, type: bridge, opts: SW0 } + - { name: net0, type: bridge, args: SW0 } switches: - name: SW0 interfaces: - - { name: net2, type: container, opts: R1 } - - { name: net0, type: container, opts: R3 } - - { name: net0, type: container, opts: R4 } + - { name: net2, type: container, args: R1 } + - { name: net0, type: container, args: R3 } + - { name: net0, type: container, args: R4 } node_configs: - name: S0 cmds: + - cmd: sysctl -w 'net.ipv6.conf.all.forwarding=1' - cmd: sysctl -w 'net.ipv6.conf.all.disable_ipv6=0' - cmd: sysctl -w 'net.ipv6.conf.default.disable_ipv6=0' - cmd: sysctl -w 'net.ipv6.conf.all.seg6_enabled=1' @@ -56,6 +57,7 @@ node_configs: - cmd: ip -6 route add fc00:c::/64 via fc00:a::1 - name: S1 cmds: + - cmd: sysctl -w 'net.ipv6.conf.all.forwarding=1' - cmd: sysctl -w 'net.ipv6.conf.all.disable_ipv6=0' - cmd: sysctl -w 'net.ipv6.conf.default.disable_ipv6=0' - cmd: sysctl -w 'net.ipv6.conf.all.seg6_enabled=1' @@ -67,6 +69,7 @@ node_configs: - cmd: ip -6 route add fc00:b::/64 via fc00:c::1 - name: R0 cmds: + - cmd: sysctl -w 'net.ipv6.conf.all.forwarding=1' - cmd: sysctl -w 'net.ipv6.conf.all.disable_ipv6=0' - cmd: sysctl -w 'net.ipv6.conf.default.disable_ipv6=0' - cmd: sysctl -w 'net.ipv6.conf.all.seg6_enabled=1' @@ -79,12 +82,13 @@ node_configs: - cmd: ip -6 route add fc00:b::/64 via fc00:12::1 - cmd: ip -6 route add fc00:c::/64 via fc00:12::1 # SRv6 operation - - cmd: >- - ip -6 r replace fc00:c::/64 encap seg6 - mode encap segs fc00:b::10,fc00:b::20,fc00:23::2 dev net1 + # - cmd: >- + # ip -6 r replace fc00:c::/64 encap seg6 + # mode encap segs fc00:b::10,fc00:b::20,fc00:23::2 dev net1 - name: R1 cmds: + - cmd: sysctl -w 'net.ipv6.conf.all.forwarding=1' - cmd: sysctl -w 'net.ipv6.conf.all.disable_ipv6=0' - cmd: sysctl -w 'net.ipv6.conf.default.disable_ipv6=0' - cmd: sysctl -w 'net.ipv6.conf.all.seg6_enabled=1' @@ -99,6 +103,7 @@ node_configs: - cmd: ip -6 route add fc00:c::/64 via fc00:23::2 - name: R2 cmds: + - cmd: sysctl -w 'net.ipv6.conf.all.forwarding=1' - cmd: sysctl -w 'net.ipv6.conf.all.disable_ipv6=0' - cmd: sysctl -w 'net.ipv6.conf.default.disable_ipv6=0' - cmd: sysctl -w 'net.ipv6.conf.all.seg6_enabled=1' @@ -107,15 +112,17 @@ node_configs: - cmd: sysctl -w 'net.ipv6.conf.net1.seg6_enabled=1' - cmd: ip -6 addr add fc00:23::2/64 dev net0 - cmd: ip -6 addr add fc00:c::1/64 dev net1 - - cmd: ip -6 route add fc00:12::/64 via fc00:12::1 + - cmd: ip -6 route add fc00:12::/64 via fc00:23::1 - cmd: ip -6 route add fc00:a::/64 via fc00:23::1 - cmd: ip -6 route add fc00:b::/64 via fc00:23::1 # SRv6 operation - - cmd: >- - ip -6 r replace fc00:a::/64 encap seg6 - mode encap segs fc00:b::20,fc00:b::10,fc00:12::2 dev net1 + # - cmd: >- + # ip -6 r replace fc00:a::/64 encap seg6 + # mode encap segs fc00:b::20,fc00:b::10,fc00:12::2 dev net1 + - name: R3 cmds: + - cmd: sysctl -w 'net.ipv6.conf.all.forwarding=1' - cmd: sysctl -w 'net.ipv6.conf.all.disable_ipv6=0' - cmd: sysctl -w 'net.ipv6.conf.default.disable_ipv6=0' - cmd: sysctl -w 'net.ipv6.conf.all.seg6_enabled=1' @@ -128,6 +135,7 @@ node_configs: - cmd: ip -6 route add fc00:c::/64 via fc00:b::1 - name: R4 cmds: + - cmd: sysctl -w 'net.ipv6.conf.all.forwarding=1' - cmd: sysctl -w 'net.ipv6.conf.all.disable_ipv6=0' - cmd: sysctl -w 'net.ipv6.conf.default.disable_ipv6=0' - cmd: sysctl -w 'net.ipv6.conf.all.seg6_enabled=1' diff --git a/examples/basic_tc/spec.yaml b/examples/basic_tc/spec.yaml index 3a3e0ca..dbfc2ee 100644 --- a/examples/basic_tc/spec.yaml +++ b/examples/basic_tc/spec.yaml @@ -3,11 +3,11 @@ nodes: - name: C0 image: slankdev/ubuntu:18.04 interfaces: - - { name: net0, type: direct, opts: C1#net0 } + - { name: net0, type: direct, args: C1#net0 } - name: C1 image: slankdev/ubuntu:18.04 interfaces: - - { name: net0, type: direct, opts: C0#net0 } + - { name: net0, type: direct, args: C0#net0 } node_configs: - name: C0 diff --git a/examples/basic_vrf/spec.yaml b/examples/basic_vrf/spec.yaml index 96c02a6..887622d 100644 --- a/examples/basic_vrf/spec.yaml +++ b/examples/basic_vrf/spec.yaml @@ -21,33 +21,33 @@ nodes: - name: R0 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R1#net0 } - - { name: net1, type: direct, opts: C00#net0 } - - { name: net2, type: direct, opts: C10#net0 } + - { name: net0, type: direct, args: R1#net0 } + - { name: net1, type: direct, args: C00#net0 } + - { name: net2, type: direct, args: C10#net0 } - name: R1 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R0#net0 } - - { name: net1, type: direct, opts: C01#net0 } - - { name: net2, type: direct, opts: C11#net0 } + - { name: net0, type: direct, args: R0#net0 } + - { name: net1, type: direct, args: C01#net0 } + - { name: net2, type: direct, args: C11#net0 } - name: C00 image: slankdev/ubuntu:18.04 interfaces: - - { name: net0, type: direct, opts: R0#net1 } + - { name: net0, type: direct, args: R0#net1 } - name: C01 image: slankdev/ubuntu:18.04 interfaces: - - { name: net0, type: direct, opts: R1#net1 } + - { name: net0, type: direct, args: R1#net1 } - name: C10 image: slankdev/ubuntu:18.04 interfaces: - - { name: net0, type: direct, opts: R0#net2 } + - { name: net0, type: direct, args: R0#net2 } - name: C11 image: slankdev/ubuntu:18.04 interfaces: - - { name: net0, type: direct, opts: R1#net2 } + - { name: net0, type: direct, args: R1#net2 } node_configs: diff --git a/examples/basic_vrrp/spec.yaml b/examples/basic_vrrp/spec.yaml index e9f3bb0..7e44c01 100644 --- a/examples/basic_vrrp/spec.yaml +++ b/examples/basic_vrrp/spec.yaml @@ -30,30 +30,30 @@ nodes: # image: slankdev/frr image: tmp interfaces: - - { name: net0, type: direct, opts: S0#net0 } - - { name: net1, type: bridge, opts: B0 } + - { name: net0, type: direct, args: S0#net0 } + - { name: net1, type: bridge, args: B0 } - name: R1 # image: slankdev/frr image: tmp interfaces: - - { name: net0, type: direct, opts: S0#net1 } - - { name: net1, type: bridge, opts: B0 } + - { name: net0, type: direct, args: S0#net1 } + - { name: net1, type: bridge, args: B0 } - name: S0 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R0#net0 } - - { name: net1, type: direct, opts: R1#net0 } + - { name: net0, type: direct, args: R0#net0 } + - { name: net1, type: direct, args: R1#net0 } - name: C0 image: slankdev/frr interfaces: - - { name: net0, type: bridge, opts: B0 } + - { name: net0, type: bridge, args: B0 } switches: - name: B0 interfaces: - - { type: container, opts: R0, name: net1 } - - { type: container, opts: R1, name: net1 } - - { type: container, opts: C0, name: net0 } + - { type: container, args: R0, name: net1 } + - { type: container, args: R1, name: net1 } + - { type: container, args: C0, name: net0 } node_configs: - name: R0 diff --git a/examples/basic_vxlan/spec.yaml b/examples/basic_vxlan/spec.yaml index 6f1a94f..093ffc8 100644 --- a/examples/basic_vxlan/spec.yaml +++ b/examples/basic_vxlan/spec.yaml @@ -22,21 +22,21 @@ nodes: - name: R0 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R1#net0 } - - { name: net1, type: direct, opts: C0#net0 } + - { name: net0, type: direct, args: R1#net0 } + - { name: net1, type: direct, args: C0#net0 } - name: R1 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R0#net0 } - - { name: net1, type: direct, opts: C1#net0 } + - { name: net0, type: direct, args: R0#net0 } + - { name: net1, type: direct, args: C1#net0 } - name: C0 image: slankdev/ubuntu:16.04 interfaces: - - { name: net0, type: direct, opts: R0#net1 } + - { name: net0, type: direct, args: R0#net1 } - name: C1 image: slankdev/ubuntu:16.04 interfaces: - - { name: net0, type: direct, opts: R1#net1 } + - { name: net0, type: direct, args: R1#net1 } node_configs: - name: R0 diff --git a/examples/basic_xdp/spec.yaml b/examples/basic_xdp/spec.yaml index fa820c4..697d070 100644 --- a/examples/basic_xdp/spec.yaml +++ b/examples/basic_xdp/spec.yaml @@ -8,16 +8,16 @@ nodes: - name: C0 image: xdptmp interfaces: - - { name: net0, type: direct, opts: C1#net0 } - - { name: net1, type: direct, opts: C2#net0 } + - { name: net0, type: direct, args: C1#net0 } + - { name: net1, type: direct, args: C2#net0 } - name: C1 image: slankdev/ubuntu:18.04 interfaces: - - { name: net0, type: direct, opts: C0#net0 } + - { name: net0, type: direct, args: C0#net0 } - name: C2 image: slankdev/ubuntu:18.04 interfaces: - - { name: net0, type: direct, opts: C0#net1 } + - { name: net0, type: direct, args: C0#net1 } preconf: - cmds: diff --git a/examples/bgp_test/spec.yaml b/examples/bgp_test/spec.yaml index 6a755d7..500c670 100644 --- a/examples/bgp_test/spec.yaml +++ b/examples/bgp_test/spec.yaml @@ -42,34 +42,34 @@ nodes: - name: R1 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: C1#net0 } - - { name: net1, type: direct, opts: R2#net0 } - - { name: net2, type: direct, opts: R3#net0 } + - { name: net0, type: direct, args: C1#net0 } + - { name: net1, type: direct, args: R2#net0 } + - { name: net2, type: direct, args: R3#net0 } - name: R2 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R1#net1 } - - { name: vnet1, type: direct, opts: DUT#ens6 } + - { name: net0, type: direct, args: R1#net1 } + - { name: vnet1, type: direct, args: DUT#ens6 } - name: R3 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R1#net2 } - - { name: vnet2, type: direct, opts: DUT#ens7 } + - { name: net0, type: direct, args: R1#net2 } + - { name: vnet2, type: direct, args: DUT#ens7 } - name: C1 image: slankdev/ubuntu:18.04 interfaces: - - { name: net0, type: direct, opts: R1#net0 } + - { name: net0, type: direct, args: R1#net0 } - name: C2 image: slankdev/ubuntu:18.04 interfaces: - - { name: vnet3, type: direct, opts: DUT#ens8 } + - { name: vnet3, type: direct, args: DUT#ens8 } - name: DUT image: slankdev/frr interfaces: - - { name: ens6, type: direct, opts: R2#vnet1} - - { name: ens7, type: direct, opts: R3#vnet2 } - - { name: ens8, type: direct, opts: C2#vnet3 } + - { name: ens6, type: direct, args: R2#vnet1} + - { name: ens7, type: direct, args: R3#vnet2 } + - { name: ens8, type: direct, args: C2#vnet3 } node_configs: diff --git a/examples/bgp_test2/spec.yaml b/examples/bgp_test2/spec.yaml index fc4c0ab..8de032c 100644 --- a/examples/bgp_test2/spec.yaml +++ b/examples/bgp_test2/spec.yaml @@ -48,34 +48,34 @@ nodes: - name: R1 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: C1#net0 } - - { name: net1, type: direct, opts: R2#net0 } - - { name: net2, type: direct, opts: R3#net0 } + - { name: net0, type: direct, args: C1#net0 } + - { name: net1, type: direct, args: R2#net0 } + - { name: net2, type: direct, args: R3#net0 } - name: R2 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R1#net1 } - - { name: vnet1, type: direct, opts: DUT#ens6 } + - { name: net0, type: direct, args: R1#net1 } + - { name: vnet1, type: direct, args: DUT#ens6 } - name: R3 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R1#net2 } - - { name: vnet2, type: direct, opts: DUT#ens7 } + - { name: net0, type: direct, args: R1#net2 } + - { name: vnet2, type: direct, args: DUT#ens7 } - name: C1 image: slankdev/ubuntu:18.04 interfaces: - - { name: net0, type: direct, opts: R1#net0 } + - { name: net0, type: direct, args: R1#net0 } - name: C2 image: slankdev/ubuntu:18.04 interfaces: - - { name: vnet3, type: direct, opts: DUT#ens8 } + - { name: vnet3, type: direct, args: DUT#ens8 } - name: DUT image: slankdev/frr interfaces: - - { name: ens6, type: direct, opts: R2#vnet1} - - { name: ens7, type: direct, opts: R3#vnet2 } - - { name: ens8, type: direct, opts: C2#vnet3 } + - { name: ens6, type: direct, args: R2#vnet1} + - { name: ens7, type: direct, args: R3#vnet2 } + - { name: ens8, type: direct, args: C2#vnet3 } node_configs: diff --git a/examples/flowspec/spec.yaml b/examples/flowspec/spec.yaml index 339f3b4..dd7176a 100644 --- a/examples/flowspec/spec.yaml +++ b/examples/flowspec/spec.yaml @@ -24,28 +24,28 @@ nodes: - name: R0 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R1#net0 } - - { name: net1, type: direct, opts: C0#net0 } - - { name: net2, type: direct, opts: R2#net0 } + - { name: net0, type: direct, args: R1#net0 } + - { name: net1, type: direct, args: C0#net0 } + - { name: net2, type: direct, args: R2#net0 } - name: R1 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R0#net0 } - - { name: net1, type: direct, opts: C1#net0 } - - { name: net2, type: direct, opts: R2#net1 } + - { name: net0, type: direct, args: R0#net0 } + - { name: net1, type: direct, args: C1#net0 } + - { name: net2, type: direct, args: R2#net1 } - name: R2 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R0#net2 } - - { name: net1, type: direct, opts: R1#net2 } + - { name: net0, type: direct, args: R0#net2 } + - { name: net1, type: direct, args: R1#net2 } - name: C0 image: slankdev/ubuntu:18.04 interfaces: - - { name: net0, type: direct, opts: R0#net1 } + - { name: net0, type: direct, args: R0#net1 } - name: C1 image: slankdev/ubuntu:18.04 interfaces: - - { name: net0, type: direct, opts: R1#net1 } + - { name: net0, type: direct, args: R1#net1 } node_configs: - name: R0 diff --git a/examples/ovs_port_vlan/spec.yaml b/examples/ovs_port_vlan/spec.yaml index 21dda3f..8ffbbbe 100644 --- a/examples/ovs_port_vlan/spec.yaml +++ b/examples/ovs_port_vlan/spec.yaml @@ -13,30 +13,30 @@ nodes: - name: C0 image: slankdev/ubuntu:16.04 - interfaces: [{ name: net0, type: direct, opts: SW0#swp0 }] + interfaces: [{ name: net0, type: direct, args: SW0#swp0 }] - name: C1 image: slankdev/ubuntu:16.04 - interfaces: [{ name: net0, type: direct, opts: SW0#swp1 }] + interfaces: [{ name: net0, type: direct, args: SW0#swp1 }] - name: C2 image: slankdev/ubuntu:16.04 - interfaces: [{ name: net0, type: direct, opts: SW1#swp0 }] + interfaces: [{ name: net0, type: direct, args: SW1#swp0 }] - name: C3 image: slankdev/ubuntu:16.04 - interfaces: [{ name: net0, type: direct, opts: SW1#swp1 }] + interfaces: [{ name: net0, type: direct, args: SW1#swp1 }] - name: SW0 image: slankdev/ovs interfaces: - - { name: swp0, type: direct, opts: C0#net0 } - - { name: swp1, type: direct, opts: C1#net0 } - - { name: swp2, type: direct, opts: SW1#swp2 } + - { name: swp0, type: direct, args: C0#net0 } + - { name: swp1, type: direct, args: C1#net0 } + - { name: swp2, type: direct, args: SW1#swp2 } - name: SW1 image: slankdev/ovs interfaces: - - { name: swp0, type: direct, opts: C2#net0 } - - { name: swp1, type: direct, opts: C3#net0 } - - { name: swp2, type: direct, opts: SW0#swp2 } + - { name: swp0, type: direct, args: C2#net0 } + - { name: swp1, type: direct, args: C3#net0 } + - { name: swp2, type: direct, args: SW0#swp2 } node_configs: - { name: C0, cmds: [ cmd: 'ip addr add 192.168.10.1/24 dev net0' ] } diff --git a/examples/test/Makefile b/examples/test/Makefile deleted file mode 100644 index 87b8c58..0000000 --- a/examples/test/Makefile +++ /dev/null @@ -1,28 +0,0 @@ - -CNS=../../bin/cns - -all: \ - test_node_interface_physnet \ - test_node_interface_bridge \ - test_node_interface_direct - -test_node_interface_physnet: - sudo ip link add veth0 type veth peer name veth1 - sudo ip link set veth1 up - sudo ip addr add 10.10.10.2/24 dev veth1 - $(CNS) -f test_node_interface_physnet.yaml init | sudo sh - $(CNS) -f test_node_interface_physnet.yaml conf | sudo sh - $(CNS) -f test_node_interface_physnet.yaml test | sudo sh - $(CNS) -f test_node_interface_physnet.yaml fini | sudo sh - -test_node_interface_bridge: - $(CNS) -f test_node_interface_bridge.yaml init | sudo sh - $(CNS) -f test_node_interface_bridge.yaml conf | sudo sh - $(CNS) -f test_node_interface_bridge.yaml test | sudo sh - $(CNS) -f test_node_interface_bridge.yaml fini | sudo sh - -test_node_interface_direct: - $(CNS) -f test_node_interface_direct.yaml init | sudo sh - $(CNS) -f test_node_interface_direct.yaml conf | sudo sh - $(CNS) -f test_node_interface_direct.yaml test | sudo sh - $(CNS) -f test_node_interface_direct.yaml fini | sudo sh diff --git a/examples/test/test_node_interface_bridge.yaml b/examples/test/test_node_interface_bridge.yaml deleted file mode 100644 index 75293bc..0000000 --- a/examples/test/test_node_interface_bridge.yaml +++ /dev/null @@ -1,49 +0,0 @@ - -nodes: - - name: C0 - image: slankdev/ubuntu:16.04 - interfaces: - - name: net0 - type: bridge - opts: B0 - - name: C1 - image: slankdev/ubuntu:16.04 - interfaces: - - name: net0 - type: bridge - opts: B0 - - name: C2 - image: slankdev/ubuntu:16.04 - interfaces: - - name: net0 - type: bridge - opts: B0 -switches: - - name: B0 - interfaces: - - name: net0 - type: container - opts: C0 - - name: net0 - type: container - opts: C1 - - name: net0 - type: container - opts: C2 - -node_configs: - - name: C0 - cmds: - - cmd: ip addr add 10.0.0.10/24 dev net0 - - name: C1 - cmds: - - cmd: ip addr add 10.0.0.11/24 dev net0 - - name: C2 - cmds: - - cmd: ip addr add 10.0.0.12/24 dev net0 - -test: - - cmds: - - cmd: docker exec C0 ping -c2 10.0.0.11 - - cmd: docker exec C1 ping -c2 10.0.0.12 - - cmd: docker exec C2 ping -c2 10.0.0.10 diff --git a/examples/test/test_node_interface_direct.yaml b/examples/test/test_node_interface_direct.yaml deleted file mode 100644 index 18d491e..0000000 --- a/examples/test/test_node_interface_direct.yaml +++ /dev/null @@ -1,26 +0,0 @@ - -nodes: - - name: C0 - image: slankdev/ubuntu:16.04 - interfaces: - - name: net0 - type: direct - opts: C1#net - - name: C1 - image: slankdev/ubuntu:16.04 - interfaces: - - name: net0 - type: direct - opts: C0#net0 - -node_configs: - - name: C0 - cmds: - - cmd: ip addr add 10.0.0.10/24 dev net0 - - name: C1 - cmds: - - cmd: ip addr add 10.0.0.11/24 dev net0 - -test: - - cmds: - - cmd: docker exec C0 ping -c2 10.0.0.11 diff --git a/examples/test/test_node_interface_physnet.yaml b/examples/test/test_node_interface_physnet.yaml deleted file mode 100644 index 1fb1771..0000000 --- a/examples/test/test_node_interface_physnet.yaml +++ /dev/null @@ -1,27 +0,0 @@ - -# Description: Testing attach physical netif to Container -# INIT: -# sudo ip link add veth0 type veth peer name veth1 -# cns spec3.yaml init | sudo sh -# docker exec C0 ip addr add 10.10.10.1/24 dev veth0 -# sudo ip link set veth1 up -# sudo ip addr add 10.10.10.2/24 dev veth1 -# ping -c2 10.10.10.1 -# FINI: -# cns spec3.yaml fini | sudo sh - -nodes: - - name: C0 - image: slankdev/ubuntu:16.04 - interfaces: - - name: veth0 - type: phys - -node_configs: - - name: C0 - cmds: - - cmd: ip addr add 10.10.10.1/24 dev veth0 - -test: - - cmds: - - cmd: ping -c2 10.10.10.1 diff --git a/projects/shownet2018/spec.yaml b/projects/shownet2018/spec.yaml index 02292e6..6feb362 100644 --- a/projects/shownet2018/spec.yaml +++ b/projects/shownet2018/spec.yaml @@ -6,50 +6,50 @@ nodes: - name: R2 image: slankdev/frr interfaces: - - { name: port-0-0-0, type: direct, opts: AS10#net0 } - - { name: port-0-0-1, type: direct, opts: R5#port-0-1-0 } - - { name: port-0-0-2, type: direct, opts: R6#port-18-0-0 } + - { name: port-0-0-0, type: direct, args: AS10#net0 } + - { name: port-0-0-1, type: direct, args: R5#port-0-1-0 } + - { name: port-0-0-2, type: direct, args: R6#port-18-0-0 } - name: R4 image: slankdev/frr interfaces: - - { name: port-6-0-0, type: direct, opts: AS10#net1 } - - { name: port-4-0-0, type: direct, opts: R5#port-0-1-2 } - - { name: port-4-0-1, type: direct, opts: R6#port-5e-0-0 } + - { name: port-6-0-0, type: direct, args: AS10#net1 } + - { name: port-4-0-0, type: direct, args: R5#port-0-1-2 } + - { name: port-4-0-1, type: direct, args: R6#port-5e-0-0 } - name: R5 image: slankdev/frr interfaces: - - { name: port-0-1-0, type: direct, opts: R2#port-0-0-1 } - - { name: port-0-1-2, type: direct, opts: R4#port-4-0-0 } - - { name: port-0-1-3, type: direct, opts: R6#port-86-0-0 } - - { name: port-0-1-4, type: bridge, opts: SW0 } + - { name: port-0-1-0, type: direct, args: R2#port-0-0-1 } + - { name: port-0-1-2, type: direct, args: R4#port-4-0-0 } + - { name: port-0-1-3, type: direct, args: R6#port-86-0-0 } + - { name: port-0-1-4, type: bridge, args: SW0 } - name: R6 image: slankdev/frr interfaces: - - { name: port-18-0-0, type: direct, opts: R2#port-0-0-2 } - - { name: port-5e-0-0, type: direct, opts: R4#port-4-0-1 } - - { name: port-86-0-0, type: direct, opts: R5#port-0-1-3 } - - { name: port-af-0-0, type: bridge, opts: SW0 } + - { name: port-18-0-0, type: direct, args: R2#port-0-0-2 } + - { name: port-5e-0-0, type: direct, args: R4#port-4-0-1 } + - { name: port-86-0-0, type: direct, args: R5#port-0-1-3 } + - { name: port-af-0-0, type: bridge, args: SW0 } - name: AS10 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R2#port-0-0-0 } - - { name: net1, type: direct, opts: R4#port-6-0-0 } + - { name: net0, type: direct, args: R2#port-0-0-0 } + - { name: net1, type: direct, args: R4#port-6-0-0 } - name: C0 image: slankdev/ubuntu:18.04 interfaces: - - { name: net0, type: bridge, opts: SW0 } + - { name: net0, type: bridge, args: SW0 } switches: - name: SW0 interfaces: - - { type: container, opts: R5, name: port-0-1-4 } - - { type: container, opts: R6, name: port-af-0-0 } - - { type: container, opts: C0, name: net0 } + - { type: container, args: R5, name: port-0-1-4 } + - { type: container, args: R6, name: port-af-0-0 } + - { type: container, args: C0, name: net0 } node_configs: diff --git a/projects/srv6_eval/README.md b/projects/srv6_eval/README.md new file mode 100644 index 0000000..936c965 --- /dev/null +++ b/projects/srv6_eval/README.md @@ -0,0 +1,42 @@ + +# SRv6 Eval + +## Functions List + +``` + Name Descriptions Tested +------------------------------------------------------------------- + T + T.Insert + T.Encaps + T.Encaps.L2 + End + End.X + End.T + End.S + End.DX6 + End.DX4 + End.DX2 + End.DX2V + End.DT6 + End.DT4 + End.DT46 + End.DT2U + End.DT2M + End.B6 + End.B6.Encaps + End.BM + End.AM + End.AD + End.AS2 + End.AS4 + End.AS6 + End.TM + End.Tmap +``` + +## MEMO + +- hoge +- fuga + diff --git a/projects/vrouter_test/spec.yaml b/projects/vrouter_test/spec.yaml index 5d6d891..d31902b 100644 --- a/projects/vrouter_test/spec.yaml +++ b/projects/vrouter_test/spec.yaml @@ -42,24 +42,24 @@ nodes: - name: R1 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: C1#net0 } - - { name: net1, type: direct, opts: R2#net0 } - - { name: net2, type: direct, opts: R3#net0 } + - { name: net0, type: direct, args: C1#net0 } + - { name: net1, type: direct, args: R2#net0 } + - { name: net2, type: direct, args: R3#net0 } - name: R2 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R1#net1 } + - { name: net0, type: direct, args: R1#net1 } - { name: vnet1, type: phys } - name: R3 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R1#net2 } + - { name: net0, type: direct, args: R1#net2 } - { name: vnet2, type: phys } - name: C1 # image: slankdev/ubuntu:18.04 image: tmp interfaces: - - { name: net0, type: direct, opts: R1#net0 } + - { name: net0, type: direct, args: R1#net0 } - name: C2 # image: slankdev/ubuntu:18.04 image: tmp diff --git a/projects/vrouter_test2/spec.yaml b/projects/vrouter_test2/spec.yaml index 1d98fee..9f1e082 100644 --- a/projects/vrouter_test2/spec.yaml +++ b/projects/vrouter_test2/spec.yaml @@ -48,23 +48,23 @@ nodes: - name: R1 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: C1#net0 } - - { name: net1, type: direct, opts: R2#net0 } - - { name: net2, type: direct, opts: R3#net0 } + - { name: net0, type: direct, args: C1#net0 } + - { name: net1, type: direct, args: R2#net0 } + - { name: net2, type: direct, args: R3#net0 } - name: R2 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R1#net1 } + - { name: net0, type: direct, args: R1#net1 } - { name: vnet1, type: phys } - name: R3 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R1#net2 } + - { name: net0, type: direct, args: R1#net2 } - { name: vnet2, type: phys } - name: C1 image: slankdev/ubuntu:18.04 interfaces: - - { name: net0, type: direct, opts: R1#net0 } + - { name: net0, type: direct, args: R1#net0 } - name: C2 image: slankdev/ubuntu:18.04 interfaces: diff --git a/projects/vrouter_test3/dut.yaml b/projects/vrouter_test3/dut.yaml index 364815b..3b8aa33 100644 --- a/projects/vrouter_test3/dut.yaml +++ b/projects/vrouter_test3/dut.yaml @@ -20,9 +20,9 @@ nodes: - name: DUT image: slankdev/frr interfaces: - - { name: port-0-6-0, type: veth, opts: pp6 } - - { name: port-0-7-0, type: veth, opts: pp7 } - - { name: port-0-8-0, type: veth, opts: pp8 } + - { name: port-0-6-0, type: veth, args: pp6 } + - { name: port-0-7-0, type: veth, args: pp7 } + - { name: port-0-8-0, type: veth, args: pp8 } node_configs: - name: DUT diff --git a/projects/vrouter_test3/spec.yaml b/projects/vrouter_test3/spec.yaml index 5c2bbb7..5ad1e22 100644 --- a/projects/vrouter_test3/spec.yaml +++ b/projects/vrouter_test3/spec.yaml @@ -52,27 +52,27 @@ nodes: - name: R1 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: C1#net0 } - - { name: net1, type: direct, opts: R2#net0 } - - { name: net2, type: direct, opts: R3#net0 } + - { name: net0, type: direct, args: C1#net0 } + - { name: net1, type: direct, args: R2#net0 } + - { name: net2, type: direct, args: R3#net0 } - name: R2 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R1#net1 } - - { name: net1, type: veth, opts: R2net1 } + - { name: net0, type: direct, args: R1#net1 } + - { name: net1, type: veth, args: R2net1 } - name: R3 image: slankdev/frr interfaces: - - { name: net0, type: direct, opts: R1#net2 } - - { name: net1, type: veth, opts: R3net1 } + - { name: net0, type: direct, args: R1#net2 } + - { name: net1, type: veth, args: R3net1 } - name: C1 image: slankdev/ubuntu:18.04 interfaces: - - { name: net0, type: direct, opts: R1#net0 } + - { name: net0, type: direct, args: R1#net0 } - name: C2 image: slankdev/ubuntu:18.04 interfaces: - - { name: net0, type: veth, opts: C2net0 } + - { name: net0, type: veth, args: C2net0 } node_configs: - name: R1 diff --git a/projects/vrouter_test4/spec.yaml b/projects/vrouter_test4/spec.yaml index 8214d2a..f08b8ca 100644 --- a/projects/vrouter_test4/spec.yaml +++ b/projects/vrouter_test4/spec.yaml @@ -23,11 +23,11 @@ nodes: - name: C0 image: slankdev/ubuntu:18.04 interfaces: - - { name: net0, type: veth, opts: C0net0 } + - { name: net0, type: veth, args: C0net0 } - name: C1 image: slankdev/ubuntu:18.04 interfaces: - - { name: net0, type: veth, opts: C1net0 } + - { name: net0, type: veth, args: C1net0 } node_configs: - name: C0 diff --git a/projects/vrouter_test4/sriov.yaml b/projects/vrouter_test4/sriov.yaml index 42f50d0..0ec71d0 100644 --- a/projects/vrouter_test4/sriov.yaml +++ b/projects/vrouter_test4/sriov.yaml @@ -4,11 +4,11 @@ nodes: - name: C0 image: slankdev/ubuntu:18.04 interfaces: - - { name: enp24s0f1, type: phys, opts: none } + - { name: enp24s0f1, type: phys, args: none } - name: C1 image: slankdev/ubuntu:18.04 interfaces: - - { name: enp59s0f1, type: phys, opts: none } + - { name: enp59s0f1, type: phys, args: none } node_configs: - name: C0 diff --git a/projects/vrouter_test_portmirror/spec.yaml b/projects/vrouter_test_portmirror/spec.yaml index 002ec24..868a4e8 100644 --- a/projects/vrouter_test_portmirror/spec.yaml +++ b/projects/vrouter_test_portmirror/spec.yaml @@ -37,15 +37,15 @@ nodes: - name: C0 image: slankdev/ubuntu:18.04 interfaces: - - { name: net0, type: veth, opts: C0net0 } + - { name: net0, type: veth, args: C0net0 } - name: C1 image: slankdev/ubuntu:18.04 interfaces: - - { name: net0, type: veth, opts: C1net0 } + - { name: net0, type: veth, args: C1net0 } - name: C2 image: slankdev/ubuntu:18.04 interfaces: - - { name: net0, type: veth, opts: C2net0 } + - { name: net0, type: veth, args: C2net0 } node_configs: diff --git a/projects/vrouter_test_vrrp/spec.yaml b/projects/vrouter_test_vrrp/spec.yaml index 28fd120..47227cf 100644 --- a/projects/vrouter_test_vrrp/spec.yaml +++ b/projects/vrouter_test_vrrp/spec.yaml @@ -31,13 +31,13 @@ nodes: - name: R0 image: slankdev/ubuntu:18.04 interfaces: - - { name: net0, type: veth, opts: R0net0 } # to_kamuee1 - - { name: net1, type: veth, opts: R0net1 } # to_kamuee2 + - { name: net0, type: veth, args: R0net0 } # to_kamuee1 + - { name: net1, type: veth, args: R0net1 } # to_kamuee2 - name: C0 image: slankdev/ubuntu:18.04 interfaces: - - { name: net0, type: veth, opts: C0net0 } + - { name: net0, type: veth, args: C0net0 } node_configs: - name: R0 diff --git a/test/Makefile b/test/Makefile new file mode 100644 index 0000000..936e9b3 --- /dev/null +++ b/test/Makefile @@ -0,0 +1,18 @@ + +TN := ../bin/tn +# TNFLAGS := --dry-run + +all: + $(TN) $(TNFLAGS) ps + $(TN) $(TNFLAGS) up + $(TN) $(TNFLAGS) down + $(TN) $(TNFLAGS) pull + $(TN) $(TNFLAGS) exec + $(TN) $(TNFLAGS) build + $(TN) $(TNFLAGS) conf + $(TN) $(TNFLAGS) reconf + $(TN) $(TNFLAGS) reup + $(TN) $(TNFLAGS) version + $(TN) $(TNFLAGS) test + $(TN) $(TNFLAGS) init + $(TN) $(TNFLAGS) img diff --git a/test/spec.yaml b/test/spec.yaml new file mode 100644 index 0000000..e3177d3 --- /dev/null +++ b/test/spec.yaml @@ -0,0 +1,37 @@ + +nodes: + - name: C0 + type: docker #optional (default:docker) + image: slankdev/ubuntu:18.04 + interfaces: + - { name: net0, type: direct, args: C1#net0 } + - { name: net1, type: bridge, args: B0 } + - { name: net2, type: phys } + - name: C1 + type: netns #optional (default:docker) + interfaces: + - { name: net0, type: direct, args: C0#net0 } + - { name: net1, type: bridge, args: B0 } + +switches: + - name: B0 + interfaces: + - { name: net0, type: docker, args: C0 } + - { name: net0, type: netns, args: C0 } + +node_configs: + - name: C0 + cmds: + - cmd: ip link set dev net0 up + - name: C1 + cmds: + - cmd: echo slankdev slankdev + - cmd: >- + echo slankdev && + echo slnakdev + +test: + - cmds: + - cmd: docker exec C0 ping -c2 10.0.0.2 + - cmd: echo slankdev slankdev + diff --git a/test/test.sh b/test/test.sh new file mode 100755 index 0000000..592c9e5 --- /dev/null +++ b/test/test.sh @@ -0,0 +1,29 @@ +#!/bin/sh +set -ue + +mkdir -p /tmp/work && cd /tmp/work +rm -rf tinet +git clone https://github.com/slankdev/tinet +cd tinet +git checkout -b work-br origin/WIP-v0.0 + +pip3 install -r requirement.txt +tn version + +cd /tmp/work/tinet/examples/basic_bfd && tn init +cd /tmp/work/tinet/examples/basic_ebgp && tn init +cd /tmp/work/tinet/examples/basic_ecmp && tn init +cd /tmp/work/tinet/examples/basic_evpn && tn init +cd /tmp/work/tinet/examples/basic_ibgp_rrg && tn init +# cd /tmp/work/tinet/examples/basic_mplsg && tn init +# cd /tmp/work/tinet/examples/basic_naptg && tn init +# cd /tmp/work/tinet/examples/basic_netnsg && tn init +# cd /tmp/work/tinet/examples/basic_ospfg && tn init +# cd /tmp/work/tinet/examples/basic_pppoe_WIPg && tn init +# cd /tmp/work/tinet/examples/basic_srmplsg && tn init +# cd /tmp/work/tinet/examples/basic_srv6g && tn init +# cd /tmp/work/tinet/examples/basic_tcg && tn init +# cd /tmp/work/tinet/examples/basic_vrfg && tn init +# cd /tmp/work/tinet/examples/basic_vrrpg && tn init +# cd /tmp/work/tinet/examples/basic_vxlang && tn init +# cd /tmp/work/tinet/examples/basic_xdpg && tn init