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."""
51 class ChainRouter(object):
52 """Could be a shared router across all chains or a chain private router."""
54 def __init__(self, manager, name, subnets, routes):
55 """Create a router for given chain."""
56 self.manager = manager
57 self.subnets = subnets
60 self.ports = [None, None]
66 LOG.error("Error creating router %s", self.name)
71 # Lookup if there is a matching router with same name
72 routers = self.manager.neutron_client.list_routers(name=self.name)
74 if routers['routers']:
75 router = routers['routers'][0]
76 # a router of same name already exists, we need to verify it has the same
79 for subnet in self.subnets:
80 if not self.get_router_interface(router['id'], subnet.network['subnets'][0]):
81 raise ChainException("Mismatch of 'subnet_id' for reused "
82 "router '{router}'.Router has no subnet id '{sub_id}'."
83 .format(router=self.name,
84 sub_id=subnet.network['subnets'][0]))
85 interfaces = self.manager.neutron_client.list_ports(device_id=router['id'])['ports']
86 for interface in interfaces:
87 if self.is_ip_in_network(
88 interface['fixed_ips'][0]['ip_address'],
89 self.manager.config.traffic_generator.tg_gateway_ip_cidrs[0]) \
90 or self.is_ip_in_network(
91 interface['fixed_ips'][0]['ip_address'],
92 self.manager.config.traffic_generator.tg_gateway_ip_cidrs[1]):
93 self.ports[0] = interface
95 self.ports[1] = interface
97 for route in self.routes:
98 if route not in router['routes']:
99 LOG.info("Mismatch of 'router' for reused router '%s'."
100 "Router has no existing route destination '%s', "
101 "and nexthop '%s'.", self.name,
102 route['destination'],
104 LOG.info("New route added to router %s for reused ", self.name)
107 'routes': self.routes
110 self.manager.neutron_client.update_router(router['id'], body)
112 LOG.info('Reusing existing router: %s', self.name)
120 'admin_state_up': True
123 router = self.manager.neutron_client.create_router(body)['router']
124 router_id = router['id']
127 for subnet in self.subnets:
128 router_interface = {'subnet_id': subnet.network['subnets'][0]}
129 self.manager.neutron_client.add_interface_router(router_id, router_interface)
130 interfaces = self.manager.neutron_client.list_ports(device_id=router_id)['ports']
131 for interface in interfaces:
132 itf = interface['fixed_ips'][0]['ip_address']
133 cidr0 = self.manager.config.traffic_generator.tg_gateway_ip_cidrs[0]
134 cidr1 = self.manager.config.traffic_generator.tg_gateway_ip_cidrs[1]
135 if self.is_ip_in_network(itf, cidr0) or self.is_ip_in_network(itf, cidr1):
136 self.ports[0] = interface
138 self.ports[1] = interface
143 'routes': self.routes
146 self.manager.neutron_client.update_router(router_id, body)
148 LOG.info('Created router: %s.', self.name)
149 self.router = self.manager.neutron_client.show_router(router_id)
153 Extract UUID of this router.
155 :return: UUID of this router
157 return self.router['id']
159 def get_router_interface(self, router_id, subnet_id):
160 interfaces = self.manager.neutron_client.list_ports(device_id=router_id)['ports']
161 matching_interface = None
162 for interface in interfaces:
163 if interface['fixed_ips'][0]['subnet_id'] == subnet_id:
164 matching_interface = interface
165 return matching_interface
167 def is_ip_in_network(self, interface_ip, cidr):
168 return IPAddress(interface_ip) in IPNetwork(cidr)
171 """Delete this router."""
172 if not self.reuse and self.router:
174 while retry < self.manager.config.generic_retry_count:
176 self.manager.neutron_client.delete_router(self.router['id'])
177 LOG.info("Deleted router: %s", self.name)
181 LOG.info('Error deleting router %s (retry %d/%d)...',
184 self.manager.config.generic_retry_count)
185 time.sleep(self.manager.config.generic_poll_sec)
186 LOG.error('Unable to delete router: %s', self.name)