OpenStack Networking (Neutron)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

1239 lines
47 KiB

  1. # Copyright 2015
  2. # All Rights Reserved.
  3. #
  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
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  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
  14. # under the License.
  15. import collections
  16. import contextlib
  17. import copy
  18. import eventlet
  19. import netaddr
  20. from neutron_lib.callbacks import events as callbacks_events
  21. from neutron_lib.callbacks import registry as callbacks_registry
  22. from neutron_lib.callbacks import resources as callbacks_resources
  23. from neutron_lib import constants as lib_const
  24. from oslo_config import cfg
  25. from oslo_log import log as logging
  26. from oslo_utils import netutils
  27. from neutron.agent import firewall
  28. from neutron.agent.linux.openvswitch_firewall import constants as ovsfw_consts
  29. from neutron.agent.linux.openvswitch_firewall import exceptions
  30. from neutron.agent.linux.openvswitch_firewall import iptables
  31. from neutron.agent.linux.openvswitch_firewall import rules
  32. from neutron.common import constants
  33. from neutron.plugins.ml2.drivers.openvswitch.agent.common import constants \
  34. as ovs_consts
  35. LOG = logging.getLogger(__name__)
  36. def _replace_register(flow_params, register_number, register_value):
  37. """Replace value from flows to given register number
  38. 'register_value' key in dictionary will be replaced by register number
  39. given by 'register_number'
  40. :param flow_params: Dictionary containing defined flows
  41. :param register_number: The number of register where value will be stored
  42. :param register_value: Key to be replaced by register number
  43. """
  44. try:
  45. reg_port = flow_params[register_value]
  46. del flow_params[register_value]
  47. flow_params['reg{:d}'.format(register_number)] = reg_port
  48. except KeyError:
  49. pass
  50. def create_reg_numbers(flow_params):
  51. """Replace reg_(port|net) values with defined register numbers"""
  52. _replace_register(flow_params, ovsfw_consts.REG_PORT, 'reg_port')
  53. _replace_register(flow_params, ovsfw_consts.REG_NET, 'reg_net')
  54. _replace_register(
  55. flow_params, ovsfw_consts.REG_REMOTE_GROUP, 'reg_remote_group')
  56. def get_tag_from_other_config(bridge, port_name):
  57. """Return tag stored in OVSDB other_config metadata.
  58. :param bridge: OVSBridge instance where port is.
  59. :param port_name: Name of the port.
  60. :raises OVSFWTagNotFound: In case tag cannot be found in OVSDB.
  61. """
  62. other_config = None
  63. try:
  64. other_config = bridge.db_get_val(
  65. 'Port', port_name, 'other_config')
  66. return int(other_config['tag'])
  67. except (KeyError, TypeError, ValueError):
  68. raise exceptions.OVSFWTagNotFound(
  69. port_name=port_name, other_config=other_config)
  70. class SecurityGroup(object):
  71. def __init__(self, id_):
  72. self.id = id_
  73. self.raw_rules = []
  74. self.remote_rules = []
  75. self.members = {}
  76. self.ports = set()
  77. def update_rules(self, rules):
  78. """Separate raw and remote rules.
  79. If a rule has a protocol field, it is normalized to a number
  80. here in order to ease later processing.
  81. """
  82. self.raw_rules = []
  83. self.remote_rules = []
  84. for rule in copy.deepcopy(rules):
  85. protocol = rule.get('protocol')
  86. if protocol is not None:
  87. if protocol.isdigit():
  88. rule['protocol'] = int(protocol)
  89. elif (rule.get('ethertype') == lib_const.IPv6 and
  90. protocol == lib_const.PROTO_NAME_ICMP):
  91. rule['protocol'] = lib_const.PROTO_NUM_IPV6_ICMP
  92. else:
  93. rule['protocol'] = lib_const.IP_PROTOCOL_MAP.get(
  94. protocol, protocol)
  95. if 'remote_group_id' in rule:
  96. self.remote_rules.append(rule)
  97. else:
  98. self.raw_rules.append(rule)
  99. def get_ethertype_filtered_addresses(self, ethertype):
  100. return self.members.get(ethertype, [])
  101. class OFPort(object):
  102. def __init__(self, port_dict, ovs_port, vlan_tag):
  103. self.id = port_dict['device']
  104. self.vlan_tag = vlan_tag
  105. self.mac = ovs_port.vif_mac
  106. self.lla_address = str(netutils.get_ipv6_addr_by_EUI64(
  107. lib_const.IPv6_LLA_PREFIX, self.mac))
  108. self.ofport = ovs_port.ofport
  109. self.sec_groups = list()
  110. self.fixed_ips = port_dict.get('fixed_ips', [])
  111. self.neutron_port_dict = port_dict.copy()
  112. self.allowed_pairs_v4 = self._get_allowed_pairs(port_dict, version=4)
  113. self.allowed_pairs_v6 = self._get_allowed_pairs(port_dict, version=6)
  114. @staticmethod
  115. def _get_allowed_pairs(port_dict, version):
  116. aap_dict = port_dict.get('allowed_address_pairs', set())
  117. return {(aap['mac_address'], aap['ip_address']) for aap in aap_dict
  118. if netaddr.IPNetwork(aap['ip_address']).version == version}
  119. @property
  120. def all_allowed_macs(self):
  121. macs = {item[0] for item in self.allowed_pairs_v4.union(
  122. self.allowed_pairs_v6)}
  123. macs.add(self.mac)
  124. return macs
  125. @property
  126. def ipv4_addresses(self):
  127. return [ip_addr for ip_addr in self.fixed_ips
  128. if netaddr.IPAddress(ip_addr).version == 4]
  129. @property
  130. def ipv6_addresses(self):
  131. return [ip_addr for ip_addr in self.fixed_ips
  132. if netaddr.IPAddress(ip_addr).version == 6]
  133. def update(self, port_dict):
  134. self.allowed_pairs_v4 = self._get_allowed_pairs(port_dict,
  135. version=4)
  136. self.allowed_pairs_v6 = self._get_allowed_pairs(port_dict,
  137. version=6)
  138. # Neighbour discovery uses LLA
  139. self.allowed_pairs_v6.add((self.mac, self.lla_address))
  140. self.fixed_ips = port_dict.get('fixed_ips', [])
  141. self.neutron_port_dict = port_dict.copy()
  142. class SGPortMap(object):
  143. def __init__(self):
  144. self.ports = {}
  145. self.sec_groups = {}
  146. # Maps port_id to ofport number
  147. self.unfiltered = {}
  148. def get_sg(self, sg_id):
  149. return self.sec_groups.get(sg_id, None)
  150. def get_or_create_sg(self, sg_id):
  151. try:
  152. sec_group = self.sec_groups[sg_id]
  153. except KeyError:
  154. sec_group = SecurityGroup(sg_id)
  155. self.sec_groups[sg_id] = sec_group
  156. return sec_group
  157. def delete_sg(self, sg_id):
  158. del self.sec_groups[sg_id]
  159. def create_port(self, port, port_dict):
  160. self.ports[port.id] = port
  161. self.update_port(port, port_dict)
  162. def update_port(self, port, port_dict):
  163. for sec_group in self.sec_groups.values():
  164. sec_group.ports.discard(port)
  165. port.sec_groups = [self.get_or_create_sg(sg_id)
  166. for sg_id in port_dict['security_groups']]
  167. for sec_group in port.sec_groups:
  168. sec_group.ports.add(port)
  169. port.update(port_dict)
  170. def remove_port(self, port):
  171. for sec_group in port.sec_groups:
  172. sec_group.ports.discard(port)
  173. del self.ports[port.id]
  174. def update_rules(self, sg_id, rules):
  175. sec_group = self.get_or_create_sg(sg_id)
  176. sec_group.update_rules(rules)
  177. def update_members(self, sg_id, members):
  178. sec_group = self.get_or_create_sg(sg_id)
  179. sec_group.members = members
  180. class ConjIdMap(object):
  181. """Handle conjunction ID allocations and deallocations."""
  182. def __new__(cls):
  183. if not hasattr(cls, '_instance'):
  184. cls._instance = super(ConjIdMap, cls).__new__(cls)
  185. return cls._instance
  186. def __init__(self):
  187. self.id_map = collections.defaultdict(self._conj_id_factory)
  188. self.id_free = collections.deque()
  189. self.max_id = 0
  190. def _conj_id_factory(self):
  191. # If there is any freed ID, use one.
  192. if self.id_free:
  193. return self.id_free.popleft()
  194. # Allocate new one. It must be divisible by 8. (See the next function.)
  195. self.max_id += 8
  196. return self.max_id
  197. def get_conj_id(self, sg_id, remote_sg_id, direction, ethertype):
  198. """Return a conjunction ID specified by the arguments.
  199. Allocate one if necessary. The returned ID is divisible by 8,
  200. as there are 4 priority levels (see rules.flow_priority_offset)
  201. and 2 conjunction IDs are needed per priority.
  202. """
  203. if direction not in [firewall.EGRESS_DIRECTION,
  204. firewall.INGRESS_DIRECTION]:
  205. raise ValueError("Invalid direction '%s'" % direction)
  206. if ethertype not in [lib_const.IPv4, lib_const.IPv6]:
  207. raise ValueError("Invalid ethertype '%s'" % ethertype)
  208. return self.id_map[(sg_id, remote_sg_id, direction, ethertype)]
  209. def delete_sg(self, sg_id):
  210. """Free all conj_ids associated with the sg_id and
  211. return a list of (remote_sg_id, conj_id), which are no longer
  212. in use.
  213. """
  214. result = []
  215. for k in list(self.id_map.keys()):
  216. if sg_id in k[0:2]:
  217. conj_id = self.id_map.pop(k)
  218. result.append((k[1], conj_id))
  219. self.id_free.append(conj_id)
  220. return result
  221. class ConjIPFlowManager(object):
  222. """Manage conj_id allocation and remote securitygroups derived
  223. conjunction flows.
  224. Flows managed by this class is of form:
  225. nw_src=10.2.3.4,reg_net=0xf00 actions=conjunction(123,1/2)
  226. These flows are managed per network and are usually per remote_group_id,
  227. but flows from different remote_group need to be merged on shared networks,
  228. where the complexity arises and this manager is needed.
  229. """
  230. def __init__(self, driver):
  231. self.conj_id_map = ConjIdMap()
  232. self.driver = driver
  233. # The following two are dict of dicts and are indexed like:
  234. # self.x[vlan_tag][(direction, ethertype)]
  235. self.conj_ids = collections.defaultdict(dict)
  236. self.flow_state = collections.defaultdict(
  237. lambda: collections.defaultdict(dict))
  238. def _build_addr_conj_id_map(self, ethertype, sg_conj_id_map):
  239. """Build a map of addr -> list of conj_ids."""
  240. addr_to_conj = collections.defaultdict(list)
  241. for remote_id, conj_id_set in sg_conj_id_map.items():
  242. remote_group = self.driver.sg_port_map.get_sg(remote_id)
  243. if not remote_group:
  244. LOG.debug('No member for SG %s', remote_id)
  245. continue
  246. for addr in remote_group.get_ethertype_filtered_addresses(
  247. ethertype):
  248. addr_to_conj[addr].extend(conj_id_set)
  249. return addr_to_conj
  250. def _update_flows_for_vlan_subr(self, direction, ethertype, vlan_tag,
  251. flow_state, addr_to_conj):
  252. """Do the actual flow updates for given direction and ethertype."""
  253. current_ips = set(flow_state.keys())
  254. self.driver.delete_flows_for_ip_addresses(
  255. current_ips - set(addr_to_conj.keys()),
  256. direction, ethertype, vlan_tag)
  257. for addr, conj_ids in addr_to_conj.items():
  258. conj_ids.sort()
  259. if flow_state.get(addr) == conj_ids:
  260. continue
  261. for flow in rules.create_flows_for_ip_address(
  262. addr, direction, ethertype, vlan_tag, conj_ids):
  263. self.driver._add_flow(**flow)
  264. def update_flows_for_vlan(self, vlan_tag):
  265. """Install action=conjunction(conj_id, 1/2) flows,
  266. which depend on IP addresses of remote_group_id.
  267. """
  268. for (direction, ethertype), sg_conj_id_map in (
  269. self.conj_ids[vlan_tag].items()):
  270. # TODO(toshii): optimize when remote_groups have
  271. # no address overlaps.
  272. addr_to_conj = self._build_addr_conj_id_map(
  273. ethertype, sg_conj_id_map)
  274. self._update_flows_for_vlan_subr(direction, ethertype, vlan_tag,
  275. self.flow_state[vlan_tag][(direction, ethertype)],
  276. addr_to_conj)
  277. self.flow_state[vlan_tag][(direction, ethertype)] = addr_to_conj
  278. def add(self, vlan_tag, sg_id, remote_sg_id, direction, ethertype,
  279. priority_offset):
  280. """Get conj_id specified by the arguments
  281. and notify the manager that
  282. (remote_sg_id, direction, ethertype, conj_id) flows need to be
  283. populated on the vlan_tag network.
  284. A caller must call update_flows_for_vlan to have the change in effect.
  285. """
  286. conj_id = self.conj_id_map.get_conj_id(
  287. sg_id, remote_sg_id, direction, ethertype) + priority_offset * 2
  288. if (direction, ethertype) not in self.conj_ids[vlan_tag]:
  289. self.conj_ids[vlan_tag][(direction, ethertype)] = (
  290. collections.defaultdict(set))
  291. self.conj_ids[vlan_tag][(direction, ethertype)][remote_sg_id].add(
  292. conj_id)
  293. return conj_id
  294. def sg_removed(self, sg_id):
  295. """Handle SG removal events.
  296. Free all conj_ids associated with the sg_id and clean up
  297. obsolete entries from the self.conj_ids map. Unlike the add
  298. method, it also updates flows.
  299. """
  300. id_list = self.conj_id_map.delete_sg(sg_id)
  301. unused_dict = collections.defaultdict(set)
  302. for remote_sg_id, conj_id in id_list:
  303. unused_dict[remote_sg_id].add(conj_id)
  304. for vlan_tag, vlan_conj_id_map in self.conj_ids.items():
  305. update = False
  306. for sg_conj_id_map in vlan_conj_id_map.values():
  307. for remote_sg_id, unused in unused_dict.items():
  308. if (remote_sg_id in sg_conj_id_map and
  309. sg_conj_id_map[remote_sg_id] & unused):
  310. sg_conj_id_map[remote_sg_id] -= unused
  311. if not sg_conj_id_map[remote_sg_id]:
  312. del sg_conj_id_map[remote_sg_id]
  313. update = True
  314. if update:
  315. self.update_flows_for_vlan(vlan_tag)
  316. class OVSFirewallDriver(firewall.FirewallDriver):
  317. REQUIRED_PROTOCOLS = [
  318. ovs_consts.OPENFLOW10,
  319. ovs_consts.OPENFLOW11,
  320. ovs_consts.OPENFLOW12,
  321. ovs_consts.OPENFLOW13,
  322. ovs_consts.OPENFLOW14,
  323. ]
  324. provides_arp_spoofing_protection = True
  325. def __init__(self, integration_bridge):
  326. """Initialize object
  327. :param integration_bridge: Bridge on which openflow rules will be
  328. applied
  329. """
  330. self.permitted_ethertypes = cfg.CONF.SECURITYGROUP.permitted_ethertypes
  331. self.int_br = self.initialize_bridge(integration_bridge)
  332. self.sg_port_map = SGPortMap()
  333. self.conj_ip_manager = ConjIPFlowManager(self)
  334. self.sg_to_delete = set()
  335. self._update_cookie = None
  336. self._deferred = False
  337. self.iptables_helper = iptables.Helper(self.int_br.br)
  338. self.iptables_helper.load_driver_if_needed()
  339. self._initialize_firewall()
  340. callbacks_registry.subscribe(
  341. self._init_firewall_callback,
  342. callbacks_resources.AGENT,
  343. callbacks_events.OVS_RESTARTED)
  344. def _init_firewall_callback(self, resource, event, trigger, **kwargs):
  345. LOG.info("Reinitialize Openvswitch firewall after OVS restart.")
  346. self._initialize_firewall()
  347. def _initialize_firewall(self):
  348. self._drop_all_unmatched_flows()
  349. self._initialize_common_flows()
  350. self._initialize_third_party_tables()
  351. @contextlib.contextmanager
  352. def update_cookie_context(self):
  353. try:
  354. self._update_cookie = self.int_br.br.request_cookie()
  355. yield
  356. finally:
  357. self.int_br.br.unset_cookie(self._update_cookie)
  358. self._update_cookie = None
  359. def security_group_updated(self, action_type, sec_group_ids,
  360. device_ids=None):
  361. """The current driver doesn't make use of this method.
  362. It exists here to avoid NotImplementedError raised from the parent
  363. class's method.
  364. """
  365. def _accept_flow(self, **flow):
  366. for f in rules.create_accept_flows(flow):
  367. self._add_flow(**f)
  368. def _add_flow(self, **kwargs):
  369. dl_type = kwargs.get('dl_type')
  370. create_reg_numbers(kwargs)
  371. if isinstance(dl_type, int):
  372. kwargs['dl_type'] = "0x{:04x}".format(dl_type)
  373. if self._update_cookie:
  374. kwargs['cookie'] = self._update_cookie
  375. if self._deferred:
  376. self.int_br.add_flow(**kwargs)
  377. else:
  378. self.int_br.br.add_flow(**kwargs)
  379. def _delete_flows(self, **kwargs):
  380. create_reg_numbers(kwargs)
  381. if self._deferred:
  382. self.int_br.delete_flows(**kwargs)
  383. else:
  384. self.int_br.br.delete_flows(**kwargs)
  385. def _strict_delete_flow(self, **kwargs):
  386. """Delete given flow right away even if bridge is deferred.
  387. Delete command will use strict delete.
  388. """
  389. create_reg_numbers(kwargs)
  390. self.int_br.br.delete_flows(strict=True, **kwargs)
  391. @staticmethod
  392. def initialize_bridge(int_br):
  393. int_br.add_protocols(*OVSFirewallDriver.REQUIRED_PROTOCOLS)
  394. return int_br.deferred(full_ordered=True, use_bundle=True)
  395. def _drop_all_unmatched_flows(self):
  396. for table in ovs_consts.OVS_FIREWALL_TABLES:
  397. self.int_br.br.add_flow(table=table, priority=0, actions='drop')
  398. def _initialize_common_flows(self):
  399. # Remove conntrack information from tracked packets
  400. self._add_flow(
  401. table=ovs_consts.BASE_EGRESS_TABLE,
  402. priority=110,
  403. ct_state=ovsfw_consts.OF_STATE_TRACKED,
  404. actions='ct_clear,'
  405. 'resubmit(,%d)' % ovs_consts.BASE_EGRESS_TABLE,
  406. )
  407. def _initialize_third_party_tables(self):
  408. self.int_br.br.add_flow(
  409. table=ovs_consts.ACCEPTED_EGRESS_TRAFFIC_NORMAL_TABLE,
  410. priority=1,
  411. actions='normal')
  412. self.int_br.br.add_flow(
  413. table=ovs_consts.ACCEPTED_EGRESS_TRAFFIC_TABLE,
  414. priority=1,
  415. actions='resubmit(,%d)' % (
  416. ovs_consts.ACCEPTED_EGRESS_TRAFFIC_NORMAL_TABLE)
  417. )
  418. for table in (ovs_consts.ACCEPTED_INGRESS_TRAFFIC_TABLE,
  419. ovs_consts.DROPPED_TRAFFIC_TABLE):
  420. self.int_br.br.add_flow(
  421. table=table, priority=0, actions='drop')
  422. def get_ovs_port(self, port_id):
  423. ovs_port = self.int_br.br.get_vif_port_by_id(port_id)
  424. if not ovs_port:
  425. raise exceptions.OVSFWPortNotFound(port_id=port_id)
  426. return ovs_port
  427. def _get_port_vlan_tag(self, port_name):
  428. return get_tag_from_other_config(self.int_br.br, port_name)
  429. def get_ofport(self, port):
  430. port_id = port['device']
  431. return self.sg_port_map.ports.get(port_id)
  432. def get_or_create_ofport(self, port):
  433. """Get ofport specified by port['device'], checking and reflecting
  434. ofport changes.
  435. If ofport is nonexistent, create and return one.
  436. """
  437. port_id = port['device']
  438. ovs_port = self.get_ovs_port(port_id)
  439. try:
  440. of_port = self.sg_port_map.ports[port_id]
  441. except KeyError:
  442. port_vlan_id = self._get_port_vlan_tag(ovs_port.port_name)
  443. of_port = OFPort(port, ovs_port, port_vlan_id)
  444. self.sg_port_map.create_port(of_port, port)
  445. else:
  446. if of_port.ofport != ovs_port.ofport:
  447. self.sg_port_map.remove_port(of_port)
  448. of_port = OFPort(port, ovs_port, of_port.vlan_tag)
  449. self.sg_port_map.create_port(of_port, port)
  450. else:
  451. self.sg_port_map.update_port(of_port, port)
  452. return of_port
  453. def is_port_managed(self, port):
  454. return port['device'] in self.sg_port_map.ports
  455. def prepare_port_filter(self, port):
  456. self.iptables_helper.cleanup_port(port)
  457. if not firewall.port_sec_enabled(port):
  458. self._initialize_egress_no_port_security(port['device'])
  459. return
  460. try:
  461. old_of_port = self.get_ofport(port)
  462. of_port = self.get_or_create_ofport(port)
  463. if old_of_port:
  464. LOG.info("Initializing port %s that was already initialized.",
  465. port['device'])
  466. self._update_flows_for_port(of_port, old_of_port)
  467. else:
  468. self._set_port_filters(of_port)
  469. except exceptions.OVSFWPortNotFound as not_found_error:
  470. LOG.info("port %(port_id)s does not exist in ovsdb: %(err)s.",
  471. {'port_id': port['device'],
  472. 'err': not_found_error})
  473. except exceptions.OVSFWTagNotFound as tag_not_found:
  474. LOG.info("Tag was not found for port %(port_id)s: %(err)s.",
  475. {'port_id': port['device'],
  476. 'err': tag_not_found})
  477. def update_port_filter(self, port):
  478. """Update rules for given port
  479. Current existing filtering rules are removed and new ones are generated
  480. based on current loaded security group rules and members.
  481. """
  482. if not firewall.port_sec_enabled(port):
  483. self.remove_port_filter(port)
  484. self._initialize_egress_no_port_security(port['device'])
  485. return
  486. elif not self.is_port_managed(port):
  487. try:
  488. self._remove_egress_no_port_security(port['device'])
  489. except exceptions.OVSFWPortNotHandled as e:
  490. LOG.debug(e)
  491. else:
  492. self.prepare_port_filter(port)
  493. return
  494. try:
  495. # Make sure delete old allowed_address_pair MACs because
  496. # allowed_address_pair MACs will be updated in
  497. # self.get_or_create_ofport(port)
  498. old_of_port = self.get_ofport(port)
  499. of_port = self.get_or_create_ofport(port)
  500. if old_of_port:
  501. self._update_flows_for_port(of_port, old_of_port)
  502. else:
  503. self._set_port_filters(of_port)
  504. except exceptions.OVSFWPortNotFound as not_found_error:
  505. LOG.info("port %(port_id)s does not exist in ovsdb: %(err)s.",
  506. {'port_id': port['device'],
  507. 'err': not_found_error})
  508. def _set_port_filters(self, of_port):
  509. self.initialize_port_flows(of_port)
  510. self.add_flows_from_rules(of_port)
  511. def _update_flows_for_port(self, of_port, old_of_port):
  512. with self.update_cookie_context():
  513. self._set_port_filters(of_port)
  514. # Flush the flows caused by changes made to deferred bridge. The reason
  515. # is that following delete_all_port_flows() call uses --strict
  516. # parameter that cannot be combined with other non-strict rules, hence
  517. # all parameters with --strict are applied right away. In order to
  518. # avoid applying delete rules with --strict *before*
  519. # _set_port_filters() we dump currently cached flows here.
  520. self.int_br.apply_flows()
  521. self.delete_all_port_flows(old_of_port)
  522. # Rewrite update cookie with default cookie
  523. self._set_port_filters(of_port)
  524. def remove_port_filter(self, port):
  525. """Remove port from firewall
  526. All flows related to this port are removed from ovs. Port is also
  527. removed from ports managed by this firewall.
  528. """
  529. if self.is_port_managed(port):
  530. of_port = self.get_ofport(port)
  531. self.delete_all_port_flows(of_port)
  532. self.sg_port_map.remove_port(of_port)
  533. for sec_group in of_port.sec_groups:
  534. self._schedule_sg_deletion_maybe(sec_group.id)
  535. def update_security_group_rules(self, sg_id, rules):
  536. self.sg_port_map.update_rules(sg_id, rules)
  537. def update_security_group_members(self, sg_id, member_ips):
  538. self.sg_port_map.update_members(sg_id, member_ips)
  539. if not member_ips:
  540. self._schedule_sg_deletion_maybe(sg_id)
  541. def _schedule_sg_deletion_maybe(self, sg_id):
  542. """Schedule possible deletion of the given SG.
  543. This function must be called when the number of ports
  544. associated to sg_id drops to zero, as it isn't possible
  545. to know SG deletions from agents due to RPC API design.
  546. """
  547. sec_group = self.sg_port_map.get_or_create_sg(sg_id)
  548. if not sec_group.members or not sec_group.ports:
  549. self.sg_to_delete.add(sg_id)
  550. def _cleanup_stale_sg(self):
  551. sg_to_delete = self.sg_to_delete
  552. self.sg_to_delete = set()
  553. for sg_id in sg_to_delete:
  554. sec_group = self.sg_port_map.get_sg(sg_id)
  555. if sec_group.members and sec_group.ports:
  556. # sec_group is still in use
  557. continue
  558. self.conj_ip_manager.sg_removed(sg_id)
  559. self.sg_port_map.delete_sg(sg_id)
  560. def process_trusted_ports(self, port_ids):
  561. """Pass packets from these ports directly to ingress pipeline."""
  562. for port_id in port_ids:
  563. self._initialize_egress_no_port_security(port_id)
  564. # yield to let other greenthreads proceed
  565. eventlet.sleep(0)
  566. def remove_trusted_ports(self, port_ids):
  567. for port_id in port_ids:
  568. try:
  569. self._remove_egress_no_port_security(port_id)
  570. except exceptions.OVSFWPortNotHandled as e:
  571. LOG.debug(e)
  572. def filter_defer_apply_on(self):
  573. self._deferred = True
  574. def filter_defer_apply_off(self):
  575. if self._deferred:
  576. self._cleanup_stale_sg()
  577. self.int_br.apply_flows()
  578. self._deferred = False
  579. @property
  580. def ports(self):
  581. return {id_: port.neutron_port_dict
  582. for id_, port in self.sg_port_map.ports.items()}
  583. def initialize_port_flows(self, port):
  584. """Set base flows for port
  585. :param port: OFPort instance
  586. """
  587. # Identify egress flow
  588. self._add_flow(
  589. table=ovs_consts.TRANSIENT_TABLE,
  590. priority=100,
  591. in_port=port.ofport,
  592. actions='set_field:{:d}->reg{:d},'
  593. 'set_field:{:d}->reg{:d},'
  594. 'resubmit(,{:d})'.format(
  595. port.ofport,
  596. ovsfw_consts.REG_PORT,
  597. port.vlan_tag,
  598. ovsfw_consts.REG_NET,
  599. ovs_consts.BASE_EGRESS_TABLE)
  600. )
  601. # Identify ingress flows
  602. for mac_addr in port.all_allowed_macs:
  603. self._add_flow(
  604. table=ovs_consts.TRANSIENT_TABLE,
  605. priority=90,
  606. dl_dst=mac_addr,
  607. dl_vlan='0x%x' % port.vlan_tag,
  608. actions='set_field:{:d}->reg{:d},'
  609. 'set_field:{:d}->reg{:d},'
  610. 'strip_vlan,resubmit(,{:d})'.format(
  611. port.ofport,
  612. ovsfw_consts.REG_PORT,
  613. port.vlan_tag,
  614. ovsfw_consts.REG_NET,
  615. ovs_consts.BASE_INGRESS_TABLE),
  616. )
  617. self._initialize_egress(port)
  618. self._initialize_ingress(port)
  619. def _initialize_egress_ipv6_icmp(self, port):
  620. for icmp_type in firewall.ICMPV6_ALLOWED_EGRESS_TYPES:
  621. self._add_flow(
  622. table=ovs_consts.BASE_EGRESS_TABLE,
  623. priority=95,
  624. in_port=port.ofport,
  625. reg_port=port.ofport,
  626. dl_type=constants.ETHERTYPE_IPV6,
  627. nw_proto=lib_const.PROTO_NUM_IPV6_ICMP,
  628. icmp_type=icmp_type,
  629. actions='resubmit(,%d)' % (
  630. ovs_consts.ACCEPTED_EGRESS_TRAFFIC_NORMAL_TABLE)
  631. )
  632. def _initialize_egress_no_port_security(self, port_id):
  633. try:
  634. ovs_port = self.get_ovs_port(port_id)
  635. vlan_tag = self._get_port_vlan_tag(ovs_port.port_name)
  636. except exceptions.OVSFWTagNotFound:
  637. # It's a patch port, don't set anything
  638. return
  639. except exceptions.OVSFWPortNotFound as not_found_e:
  640. LOG.error("Initializing unfiltered port %(port_id)s that does not "
  641. "exist in ovsdb: %(err)s.",
  642. {'port_id': port_id,
  643. 'err': not_found_e})
  644. return
  645. self.sg_port_map.unfiltered[port_id] = ovs_port.ofport
  646. self._add_flow(
  647. table=ovs_consts.TRANSIENT_TABLE,
  648. priority=100,
  649. in_port=ovs_port.ofport,
  650. actions='set_field:%d->reg%d,'
  651. 'set_field:%d->reg%d,'
  652. 'resubmit(,%d)' % (
  653. ovs_port.ofport,
  654. ovsfw_consts.REG_PORT,
  655. vlan_tag,
  656. ovsfw_consts.REG_NET,
  657. ovs_consts.ACCEPT_OR_INGRESS_TABLE)
  658. )
  659. self._add_flow(
  660. table=ovs_consts.ACCEPT_OR_INGRESS_TABLE,
  661. priority=80,
  662. reg_port=ovs_port.ofport,
  663. actions='resubmit(,%d)' % (
  664. ovs_consts.ACCEPTED_EGRESS_TRAFFIC_NORMAL_TABLE)
  665. )
  666. def _remove_egress_no_port_security(self, port_id):
  667. try:
  668. ofport = self.sg_port_map.unfiltered[port_id]
  669. except KeyError:
  670. raise exceptions.OVSFWPortNotHandled(port_id=port_id)
  671. self._delete_flows(
  672. table=ovs_consts.TRANSIENT_TABLE,
  673. in_port=ofport
  674. )
  675. self._delete_flows(
  676. table=ovs_consts.ACCEPT_OR_INGRESS_TABLE,
  677. reg_port=ofport
  678. )
  679. del self.sg_port_map.unfiltered[port_id]
  680. def _initialize_egress(self, port):
  681. """Identify egress traffic and send it to egress base"""
  682. self._initialize_egress_ipv6_icmp(port)
  683. # Apply mac/ip pairs for IPv4
  684. allowed_pairs = port.allowed_pairs_v4.union(
  685. {(port.mac, ip_addr) for ip_addr in port.ipv4_addresses})
  686. for mac_addr, ip_addr in allowed_pairs:
  687. self._add_flow(
  688. table=ovs_consts.BASE_EGRESS_TABLE,
  689. priority=95,
  690. in_port=port.ofport,
  691. reg_port=port.ofport,
  692. dl_src=mac_addr,
  693. dl_type=constants.ETHERTYPE_ARP,
  694. arp_spa=ip_addr,
  695. actions='resubmit(,%d)' % (
  696. ovs_consts.ACCEPTED_EGRESS_TRAFFIC_NORMAL_TABLE)
  697. )
  698. self._add_flow(
  699. table=ovs_consts.BASE_EGRESS_TABLE,
  700. priority=65,
  701. reg_port=port.ofport,
  702. dl_type=constants.ETHERTYPE_IP,
  703. in_port=port.ofport,
  704. dl_src=mac_addr,
  705. nw_src=ip_addr,
  706. actions='ct(table={:d},zone=NXM_NX_REG{:d}[0..15])'.format(
  707. ovs_consts.RULES_EGRESS_TABLE,
  708. ovsfw_consts.REG_NET)
  709. )
  710. # Apply mac/ip pairs for IPv6
  711. allowed_pairs = port.allowed_pairs_v6.union(
  712. {(port.mac, ip_addr) for ip_addr in port.ipv6_addresses})
  713. for mac_addr, ip_addr in allowed_pairs:
  714. self._add_flow(
  715. table=ovs_consts.BASE_EGRESS_TABLE,
  716. priority=65,
  717. reg_port=port.ofport,
  718. in_port=port.ofport,
  719. dl_type=constants.ETHERTYPE_IPV6,
  720. dl_src=mac_addr,
  721. ipv6_src=ip_addr,
  722. actions='ct(table={:d},zone=NXM_NX_REG{:d}[0..15])'.format(
  723. ovs_consts.RULES_EGRESS_TABLE,
  724. ovsfw_consts.REG_NET)
  725. )
  726. # DHCP discovery
  727. for dl_type, src_port, dst_port in (
  728. (constants.ETHERTYPE_IP, 68, 67),
  729. (constants.ETHERTYPE_IPV6, 546, 547)):
  730. self._add_flow(
  731. table=ovs_consts.BASE_EGRESS_TABLE,
  732. priority=80,
  733. reg_port=port.ofport,
  734. in_port=port.ofport,
  735. dl_type=dl_type,
  736. nw_proto=lib_const.PROTO_NUM_UDP,
  737. tp_src=src_port,
  738. tp_dst=dst_port,
  739. actions='resubmit(,{:d})'.format(
  740. ovs_consts.ACCEPT_OR_INGRESS_TABLE)
  741. )
  742. # Ban dhcp service running on an instance
  743. for dl_type, src_port, dst_port in (
  744. (constants.ETHERTYPE_IP, 67, 68),
  745. (constants.ETHERTYPE_IPV6, 547, 546)):
  746. self._add_flow(
  747. table=ovs_consts.BASE_EGRESS_TABLE,
  748. priority=70,
  749. in_port=port.ofport,
  750. reg_port=port.ofport,
  751. dl_type=dl_type,
  752. nw_proto=lib_const.PROTO_NUM_UDP,
  753. tp_src=src_port,
  754. tp_dst=dst_port,
  755. actions='resubmit(,%d)' % ovs_consts.DROPPED_TRAFFIC_TABLE
  756. )
  757. # Drop Router Advertisements from instances
  758. self._add_flow(
  759. table=ovs_consts.BASE_EGRESS_TABLE,
  760. priority=70,
  761. in_port=port.ofport,
  762. reg_port=port.ofport,
  763. dl_type=constants.ETHERTYPE_IPV6,
  764. nw_proto=lib_const.PROTO_NUM_IPV6_ICMP,
  765. icmp_type=lib_const.ICMPV6_TYPE_RA,
  766. actions='resubmit(,%d)' % ovs_consts.DROPPED_TRAFFIC_TABLE
  767. )
  768. # Allow custom ethertypes
  769. for permitted_ethertype in self.permitted_ethertypes:
  770. if permitted_ethertype[:2] == '0x':
  771. try:
  772. hex_ethertype = hex(int(permitted_ethertype, base=16))
  773. action = ('resubmit(,%d)' %
  774. ovs_consts.ACCEPTED_EGRESS_TRAFFIC_NORMAL_TABLE)
  775. self._add_flow(
  776. table=ovs_consts.BASE_EGRESS_TABLE,
  777. priority=95,
  778. dl_type=hex_ethertype,
  779. reg_port=port.ofport,
  780. actions=action
  781. )
  782. continue
  783. except ValueError:
  784. pass
  785. LOG.warning("Custom ethertype %(permitted_ethertype)s is not "
  786. "a hexadecimal number.",
  787. {'permitted_ethertype': permitted_ethertype})
  788. # Drop all remaining egress connections
  789. self._add_flow(
  790. table=ovs_consts.BASE_EGRESS_TABLE,
  791. priority=10,
  792. in_port=port.ofport,
  793. reg_port=port.ofport,
  794. actions='ct_clear,'
  795. 'resubmit(,%d)' % ovs_consts.DROPPED_TRAFFIC_TABLE
  796. )
  797. # Fill in accept_or_ingress table by checking that traffic is ingress
  798. # and if not, accept it
  799. for mac_addr in port.all_allowed_macs:
  800. self._add_flow(
  801. table=ovs_consts.ACCEPT_OR_INGRESS_TABLE,
  802. priority=100,
  803. dl_dst=mac_addr,
  804. reg_net=port.vlan_tag,
  805. actions='set_field:{:d}->reg{:d},resubmit(,{:d})'.format(
  806. port.ofport,
  807. ovsfw_consts.REG_PORT,
  808. ovs_consts.BASE_INGRESS_TABLE),
  809. )
  810. for ethertype in [constants.ETHERTYPE_IP, constants.ETHERTYPE_IPV6]:
  811. self._add_flow(
  812. table=ovs_consts.ACCEPT_OR_INGRESS_TABLE,
  813. priority=90,
  814. dl_type=ethertype,
  815. reg_port=port.ofport,
  816. ct_state=ovsfw_consts.OF_STATE_NEW_NOT_ESTABLISHED,
  817. actions='ct(commit,zone=NXM_NX_REG{:d}[0..15]),'
  818. 'resubmit(,{:d})'.format(
  819. ovsfw_consts.REG_NET,
  820. ovs_consts.ACCEPTED_EGRESS_TRAFFIC_TABLE)
  821. )
  822. self._add_flow(
  823. table=ovs_consts.ACCEPT_OR_INGRESS_TABLE,
  824. priority=80,
  825. reg_port=port.ofport,
  826. actions='resubmit(,%d)' % (
  827. ovs_consts.ACCEPTED_EGRESS_TRAFFIC_NORMAL_TABLE)
  828. )
  829. def _initialize_tracked_egress(self, port):
  830. # Drop invalid packets
  831. self._add_flow(
  832. table=ovs_consts.RULES_EGRESS_TABLE,
  833. priority=50,
  834. ct_state=ovsfw_consts.OF_STATE_INVALID,
  835. actions='resubmit(,%d)' % ovs_consts.DROPPED_TRAFFIC_TABLE
  836. )
  837. # Drop traffic for removed sg rules
  838. self._add_flow(
  839. table=ovs_consts.RULES_EGRESS_TABLE,
  840. priority=50,
  841. reg_port=port.ofport,
  842. ct_mark=ovsfw_consts.CT_MARK_INVALID,
  843. actions='resubmit(,%d)' % ovs_consts.DROPPED_TRAFFIC_TABLE
  844. )
  845. for state in (
  846. ovsfw_consts.OF_STATE_ESTABLISHED_REPLY,
  847. ovsfw_consts.OF_STATE_RELATED,
  848. ):
  849. self._add_flow(
  850. table=ovs_consts.RULES_EGRESS_TABLE,
  851. priority=50,
  852. ct_state=state,
  853. ct_mark=ovsfw_consts.CT_MARK_NORMAL,
  854. reg_port=port.ofport,
  855. ct_zone=port.vlan_tag,
  856. actions='resubmit(,%d)' % (
  857. ovs_consts.ACCEPTED_EGRESS_TRAFFIC_NORMAL_TABLE)
  858. )
  859. self._add_flow(
  860. table=ovs_consts.RULES_EGRESS_TABLE,
  861. priority=40,
  862. reg_port=port.ofport,
  863. ct_state=ovsfw_consts.OF_STATE_NOT_ESTABLISHED,
  864. actions='resubmit(,%d)' % ovs_consts.DROPPED_TRAFFIC_TABLE
  865. )
  866. for ethertype in [constants.ETHERTYPE_IP, constants.ETHERTYPE_IPV6]:
  867. self._add_flow(
  868. table=ovs_consts.RULES_EGRESS_TABLE,
  869. priority=40,
  870. dl_type=ethertype,
  871. reg_port=port.ofport,
  872. ct_state=ovsfw_consts.OF_STATE_ESTABLISHED,
  873. actions="ct(commit,zone=NXM_NX_REG{:d}[0..15],"
  874. "exec(set_field:{:s}->ct_mark))".format(
  875. ovsfw_consts.REG_NET,
  876. ovsfw_consts.CT_MARK_INVALID)
  877. )
  878. def _initialize_ingress_ipv6_icmp(self, port):
  879. for icmp_type in firewall.ICMPV6_ALLOWED_INGRESS_TYPES:
  880. self._add_flow(
  881. table=ovs_consts.BASE_INGRESS_TABLE,
  882. priority=100,
  883. reg_port=port.ofport,
  884. dl_type=constants.ETHERTYPE_IPV6,
  885. nw_proto=lib_const.PROTO_NUM_IPV6_ICMP,
  886. icmp_type=icmp_type,
  887. actions='output:{:d}'.format(port.ofport)
  888. )
  889. def _initialize_ingress(self, port):
  890. # Allow incoming ARPs
  891. self._add_flow(
  892. table=ovs_consts.BASE_INGRESS_TABLE,
  893. priority=100,
  894. dl_type=constants.ETHERTYPE_ARP,
  895. reg_port=port.ofport,
  896. actions='output:{:d}'.format(port.ofport)
  897. )
  898. self._initialize_ingress_ipv6_icmp(port)
  899. # DHCP offers
  900. for dl_type, src_port, dst_port in (
  901. (constants.ETHERTYPE_IP, 67, 68),
  902. (constants.ETHERTYPE_IPV6, 547, 546)):
  903. self._add_flow(
  904. table=ovs_consts.BASE_INGRESS_TABLE,
  905. priority=95,
  906. reg_port=port.ofport,
  907. dl_type=dl_type,
  908. nw_proto=lib_const.PROTO_NUM_UDP,
  909. tp_src=src_port,
  910. tp_dst=dst_port,
  911. actions='output:{:d}'.format(port.ofport)
  912. )
  913. # Track untracked
  914. for dl_type in (constants.ETHERTYPE_IP, constants.ETHERTYPE_IPV6):
  915. self._add_flow(
  916. table=ovs_consts.BASE_INGRESS_TABLE,
  917. priority=90,
  918. reg_port=port.ofport,
  919. dl_type=dl_type,
  920. ct_state=ovsfw_consts.OF_STATE_NOT_TRACKED,
  921. actions='ct(table={:d},zone=NXM_NX_REG{:d}[0..15])'.format(
  922. ovs_consts.RULES_INGRESS_TABLE,
  923. ovsfw_consts.REG_NET)
  924. )
  925. self._add_flow(
  926. table=ovs_consts.BASE_INGRESS_TABLE,
  927. ct_state=ovsfw_consts.OF_STATE_TRACKED,
  928. priority=80,
  929. reg_port=port.ofport,
  930. actions='resubmit(,{:d})'.format(ovs_consts.RULES_INGRESS_TABLE)
  931. )
  932. def _initialize_tracked_ingress(self, port):
  933. # Drop invalid packets
  934. self._add_flow(
  935. table=ovs_consts.RULES_INGRESS_TABLE,
  936. priority=50,
  937. ct_state=ovsfw_consts.OF_STATE_INVALID,
  938. actions='resubmit(,%d)' % ovs_consts.DROPPED_TRAFFIC_TABLE
  939. )
  940. # Drop traffic for removed sg rules
  941. self._add_flow(
  942. table=ovs_consts.RULES_INGRESS_TABLE,
  943. priority=50,
  944. reg_port=port.ofport,
  945. ct_mark=ovsfw_consts.CT_MARK_INVALID,
  946. actions='resubmit(,%d)' % ovs_consts.DROPPED_TRAFFIC_TABLE
  947. )
  948. # Allow established and related connections
  949. for state in (ovsfw_consts.OF_STATE_ESTABLISHED_REPLY,
  950. ovsfw_consts.OF_STATE_RELATED):
  951. self._add_flow(
  952. table=ovs_consts.RULES_INGRESS_TABLE,
  953. priority=50,
  954. reg_port=port.ofport,
  955. ct_state=state,
  956. ct_mark=ovsfw_consts.CT_MARK_NORMAL,
  957. ct_zone=port.vlan_tag,
  958. actions='output:{:d}'.format(port.ofport)
  959. )
  960. self._add_flow(
  961. table=ovs_consts.RULES_INGRESS_TABLE,
  962. priority=40,
  963. reg_port=port.ofport,
  964. ct_state=ovsfw_consts.OF_STATE_NOT_ESTABLISHED,
  965. actions='resubmit(,%d)' % ovs_consts.DROPPED_TRAFFIC_TABLE
  966. )
  967. for ethertype in [constants.ETHERTYPE_IP, constants.ETHERTYPE_IPV6]:
  968. self._add_flow(
  969. table=ovs_consts.RULES_INGRESS_TABLE,
  970. priority=40,
  971. dl_type=ethertype,
  972. reg_port=port.ofport,
  973. ct_state=ovsfw_consts.OF_STATE_ESTABLISHED,
  974. actions="ct(commit,zone=NXM_NX_REG{:d}[0..15],"
  975. "exec(set_field:{:s}->ct_mark))".format(
  976. ovsfw_consts.REG_NET,
  977. ovsfw_consts.CT_MARK_INVALID)
  978. )
  979. def _add_non_ip_conj_flows(self, port):
  980. """Install conjunction flows that don't depend on IP address of remote
  981. groups, which consist of actions=conjunction(conj_id, 2/2) flows and
  982. actions=accept flows.
  983. The remaining part is done by ConjIPFlowManager.
  984. """
  985. port_rules = collections.defaultdict(list)
  986. for sec_group_id, rule in (
  987. self._create_remote_rules_generator_for_port(port)):
  988. direction = rule['direction']
  989. ethertype = rule['ethertype']
  990. protocol = rule.get('protocol')
  991. priority_offset = rules.flow_priority_offset(rule)
  992. conj_id = self.conj_ip_manager.add(port.vlan_tag, sec_group_id,
  993. rule['remote_group_id'],
  994. direction, ethertype,
  995. priority_offset)
  996. LOG.debug("Created conjunction %(conj_id)s for SG %(sg_id)s "
  997. "referencing remote SG ID %(remote_sg_id)s on port "
  998. "%(port_id)s.",
  999. {'conj_id': conj_id,
  1000. 'sg_id': sec_group_id,
  1001. 'remote_sg_id': rule['remote_group_id'],
  1002. 'port_id': port.id})
  1003. rule1 = rule.copy()
  1004. del rule1['remote_group_id']
  1005. port_rules_key = (direction, ethertype, protocol)
  1006. port_rules[port_rules_key].append((rule1, conj_id))
  1007. for (direction, ethertype, protocol), rule_conj_list in (
  1008. port_rules.items()):
  1009. all_conj_ids = set()
  1010. for rule, conj_id in rule_conj_list:
  1011. all_conj_ids.add(conj_id)
  1012. if protocol in [lib_const.PROTO_NUM_SCTP,
  1013. lib_const.PROTO_NUM_TCP,
  1014. lib_const.PROTO_NUM_UDP]:
  1015. rule_conj_list = rules.merge_port_ranges(rule_conj_list)
  1016. else:
  1017. rule_conj_list = rules.merge_common_rules(rule_conj_list)
  1018. for rule, conj_ids in rule_conj_list:
  1019. flows = rules.create_flows_from_rule_and_port(
  1020. rule, port, conjunction=True)
  1021. for flow in rules.substitute_conjunction_actions(
  1022. flows, 2, conj_ids):
  1023. self._add_flow(**flow)
  1024. # Install accept flows and store conj_id to reg7 for future process
  1025. for conj_id in all_conj_ids:
  1026. for flow in rules.create_conj_flows(
  1027. port, conj_id, direction, ethertype):
  1028. flow['actions'] = "set_field:{:d}->reg{:d},{:s}".format(
  1029. flow['conj_id'],
  1030. ovsfw_consts.REG_REMOTE_GROUP,
  1031. flow['actions']
  1032. )
  1033. self._add_flow(**flow)
  1034. def add_flows_from_rules(self, port):
  1035. self._initialize_tracked_ingress(port)
  1036. self._initialize_tracked_egress(port)
  1037. LOG.debug('Creating flow rules for port %s that is port %d in OVS',
  1038. port.id, port.ofport)
  1039. for rule in self._create_rules_generator_for_port(port):
  1040. # NOTE(toshii): A better version of merge_common_rules and
  1041. # its friend should be applied here in order to avoid
  1042. # overlapping flows.
  1043. flows = rules.create_flows_from_rule_and_port(rule, port)
  1044. LOG.debug("RULGEN: Rules generated for flow %s are %s",
  1045. rule, flows)
  1046. for flow in flows:
  1047. self._accept_flow(**flow)
  1048. self._add_non_ip_conj_flows(port)
  1049. self.conj_ip_manager.update_flows_for_vlan(port.vlan_tag)
  1050. def _create_rules_generator_for_port(self, port):
  1051. for sec_group in port.sec_groups:
  1052. for rule in sec_group.raw_rules:
  1053. yield rule
  1054. def _create_remote_rules_generator_for_port(self, port):
  1055. for sec_group in port.sec_groups:
  1056. for rule in sec_group.remote_rules:
  1057. yield sec_group.id, rule
  1058. def delete_all_port_flows(self, port):
  1059. """Delete all flows for given port"""
  1060. for mac_addr in port.all_allowed_macs:
  1061. self._strict_delete_flow(priority=90,
  1062. table=ovs_consts.TRANSIENT_TABLE,
  1063. dl_dst=mac_addr,
  1064. dl_vlan=port.vlan_tag)
  1065. self._delete_flows(table=ovs_consts.ACCEPT_OR_INGRESS_TABLE,
  1066. dl_dst=mac_addr, reg_net=port.vlan_tag)
  1067. self._strict_delete_flow(priority=100,
  1068. table=ovs_consts.TRANSIENT_TABLE,
  1069. in_port=port.ofport)
  1070. self._delete_flows(reg_port=port.ofport)
  1071. def delete_flows_for_ip_addresses(
  1072. self, ip_addresses, direction, ethertype, vlan_tag):
  1073. for ip_addr in ip_addresses:
  1074. # Generate deletion template with bogus conj_id.
  1075. flows = rules.create_flows_for_ip_address(
  1076. ip_addr, direction, ethertype, vlan_tag, [0])
  1077. for f in flows:
  1078. # The following del statements are partly for
  1079. # complying the OpenFlow spec. It forbids the use of
  1080. # these field in non-strict delete flow messages, and
  1081. # the actions field is bogus anyway.
  1082. del f['actions']
  1083. del f['priority']
  1084. self._delete_flows(**f)