2 # Copyright 2018 Cisco Systems, Inc. All rights reserved.
4 # Licensed under the Apache License, Version 2.0 (the "License"); you may
5 # not use this file except in compliance with the License. You may obtain
6 # a copy of the License at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 # License for the specific language governing permissions and limitations
17 # This module takes care of chaining routers
19 """NFVBENCH CHAIN DISCOVERY/STAGING.
21 This module takes care of staging/discovering resources that are participating in a
22 L3 benchmarking session: routers, networks, ports, routes.
23 If a resource is discovered with the same name, it will be reused.
24 Otherwise it will be created.
26 Once created/discovered, instances are checked to be in the active state (ready to pass traffic)
27 Configuration parameters that will influence how these resources are staged/related:
28 - openstack or no openstack
31 - number of VNF in each chain (PVP, PVVP)
32 - SRIOV and middle port SRIOV for port types
33 - whether networks are shared across chains or not
35 There is not traffic generation involved in this module.
39 from netaddr import IPAddress
40 from netaddr import IPNetwork
45 class ChainException(Exception):
46 """Exception while operating the chains."""
48 class ChainRouter(object):
49 """Could be a shared router across all chains or a chain private router."""
51 def __init__(self, manager, name, subnets, routes):
52 """Create a router for given chain."""
53 self.manager = manager
54 self.subnets = subnets
57 self.ports = [None, None]
63 LOG.error("Error creating router %s", self.name)
68 # Lookup if there is a matching router with same name
69 routers = self.manager.neutron_client.list_routers(name=self.name)
71 if routers['routers']:
72 router = routers['routers'][0]
73 # a router of same name already exists, we need to verify it has the same
76 for subnet in self.subnets:
77 if not self.get_router_interface(router['id'], subnet.network['subnets'][0]):
78 raise ChainException("Mismatch of 'subnet_id' for reused "
79 "router '{router}'.Router has no subnet id '{sub_id}'."
80 .format(router=self.name,
81 sub_id=subnet.network['subnets'][0]))
82 interfaces = self.manager.neutron_client.list_ports(device_id=router['id'])['ports']
83 for interface in interfaces:
84 if self.is_ip_in_network(
85 interface['fixed_ips'][0]['ip_address'],
86 self.manager.config.traffic_generator.tg_gateway_ip_cidrs[0]) \
87 or self.is_ip_in_network(
88 interface['fixed_ips'][0]['ip_address'],
89 self.manager.config.traffic_generator.tg_gateway_ip_cidrs[1]):
90 self.ports[0] = interface
92 self.ports[1] = interface
94 for route in self.routes:
95 if route not in router['routes']:
96 LOG.info("Mismatch of 'router' for reused router '%s'."
97 "Router has no existing route destination '%s', "
98 "and nexthop '%s'.", self.name,
101 LOG.info("New route added to router %s for reused ", self.name)
104 'routes': self.routes
107 self.manager.neutron_client.update_router(router['id'], body)
109 LOG.info('Reusing existing router: %s', self.name)
117 'admin_state_up': True
120 router = self.manager.neutron_client.create_router(body)['router']
121 router_id = router['id']
124 for subnet in self.subnets:
125 router_interface = {'subnet_id': subnet.network['subnets'][0]}
126 self.manager.neutron_client.add_interface_router(router_id, router_interface)
127 interfaces = self.manager.neutron_client.list_ports(device_id=router_id)['ports']
128 for interface in interfaces:
129 itf = interface['fixed_ips'][0]['ip_address']
130 cidr0 = self.manager.config.traffic_generator.tg_gateway_ip_cidrs[0]
131 cidr1 = self.manager.config.traffic_generator.tg_gateway_ip_cidrs[1]
132 if self.is_ip_in_network(itf, cidr0) or self.is_ip_in_network(itf, cidr1):
133 self.ports[0] = interface
135 self.ports[1] = interface
140 'routes': self.routes
143 self.manager.neutron_client.update_router(router_id, body)
145 LOG.info('Created router: %s.', self.name)
146 self.router = self.manager.neutron_client.show_router(router_id)
150 Extract UUID of this router.
152 :return: UUID of this router
154 return self.router['id']
156 def get_router_interface(self, router_id, subnet_id):
157 interfaces = self.manager.neutron_client.list_ports(device_id=router_id)['ports']
158 matching_interface = None
159 for interface in interfaces:
160 if interface['fixed_ips'][0]['subnet_id'] == subnet_id:
161 matching_interface = interface
162 return matching_interface
164 def is_ip_in_network(self, interface_ip, cidr):
165 return IPAddress(interface_ip) in IPNetwork(cidr)
168 """Delete this router."""
169 if not self.reuse and self.router:
171 while retry < self.manager.config.generic_retry_count:
173 self.manager.neutron_client.delete_router(self.router['id'])
174 LOG.info("Deleted router: %s", self.name)
178 LOG.info('Error deleting router %s (retry %d/%d)...',
181 self.manager.config.generic_retry_count)
182 time.sleep(self.manager.config.generic_poll_sec)
183 LOG.error('Unable to delete router: %s', self.name)