def ensure_default_ovs_flows(ovn_bridge_mappings, cookie): cookie_id = ("cookie={}/-1").format(cookie) for bridge in ovn_bridge_mappings: ovs_port = ovs_cmd('ovs-vsctl', ['list-ports', bridge])[0].rstrip() if not ovs_port: continue ovs_ofport = ovs_cmd( 'ovs-vsctl', ['get', 'Interface', ovs_port, 'ofport'] )[0].rstrip() flow_filter = ('{},in_port={}').format(cookie_id, ovs_ofport) current_flows = ovs_cmd( 'ovs-ofctl', ['dump-flows', bridge, flow_filter] )[0].split('\n')[1:-1] if len(current_flows) == 1: # assume the rule is the right one as it has the right cookie # and in_port continue with pyroute2.NDB() as ndb: flow = ("cookie={},priority=900,ip,in_port={}," "actions=mod_dl_dst:{},NORMAL".format( cookie, ovs_ofport, ndb.interfaces[bridge]['address'])) flow_v6 = ("cookie={},priority=900,ipv6,in_port={}," "actions=mod_dl_dst:{},NORMAL".format( cookie, ovs_ofport, ndb.interfaces[bridge]['address'])) ovs_cmd('ovs-ofctl', ['add-flow', bridge, flow]) ovs_cmd('ovs-ofctl', ['add-flow', bridge, flow_v6]) # Remove unneeded flows port = 'in_port={}'.format(ovs_ofport) current_flows = ovs_cmd( 'ovs-ofctl', ['dump-flows', bridge, cookie_id] )[0].split('\n')[1:-1] for flow in current_flows: if not flow or port in flow: continue in_port = flow.split("in_port=")[1].split(" ")[0] del_flow = ('{},in_port={}').format(cookie_id, in_port) ovs_cmd('ovs-ofctl', ['del-flows', bridge, del_flow])
def sync(self): self.ovn_local_cr_lrps = {} self.ovn_local_lrps = set([]) self.ovn_routing_tables_routes = collections.defaultdict() LOG.debug("Ensuring VRF configuration for advertising routes") # Create VRF linux_net.ensure_vrf(constants.OVN_BGP_VRF, constants.OVN_BGP_VRF_TABLE) # Create OVN dummy device linux_net.ensure_ovn_device(constants.OVN_BGP_NIC, constants.OVN_BGP_VRF) LOG.debug("Configuring br-ex default rule and routing tables for " "each provider network") flows_info = {} # 1) Get bridge mappings: xxxx:br-ex,yyyy:br-ex2 bridge_mappings = self.ovs_idl.get_ovn_bridge_mappings() # 2) Get macs for bridge mappings extra_routes = {} with pyroute2.NDB() as ndb: for bridge_mapping in bridge_mappings: network = bridge_mapping.split(":")[0] bridge = bridge_mapping.split(":")[1] self.ovn_bridge_mappings[network] = bridge if not extra_routes.get(bridge): extra_routes[bridge] = ( linux_net.ensure_routing_table_for_bridge( self.ovn_routing_tables, bridge)) vlan_tag = self.sb_idl.get_network_vlan_tag_by_network_name( network) if vlan_tag: vlan_tag = vlan_tag[0] linux_net.ensure_vlan_device_for_network(bridge, vlan_tag) if flows_info.get(bridge): continue flows_info[bridge] = { 'mac': ndb.interfaces[bridge]['address'], 'in_port': set([])} # 3) Get in_port for bridge mappings (br-ex, br-ex2) ovs.get_ovs_flows_info(bridge, flows_info, constants.OVS_RULE_COOKIE) # 4) Add/Remove flows for each bridge mappings ovs.remove_extra_ovs_flows(flows_info, constants.OVS_RULE_COOKIE) LOG.debug("Syncing current routes.") exposed_ips = linux_net.get_exposed_ips(constants.OVN_BGP_NIC) # get the rules pointing to ovn bridges ovn_ip_rules = linux_net.get_ovn_ip_rules( self.ovn_routing_tables.values()) # add missing routes/ips for fips/provider VMs ports = self.sb_idl.get_ports_on_chassis(self.chassis) for port in ports: self._ensure_port_exposed(port, exposed_ips, ovn_ip_rules) # add missing route/ips for tenant network VMs if self._expose_tenant_networks: for cr_lrp_info in self.ovn_local_cr_lrps.values(): lrp_ports = self.sb_idl.get_lrp_ports_for_router( cr_lrp_info['router_datapath']) for lrp in lrp_ports: if lrp.chassis: continue self._ensure_network_exposed( lrp, cr_lrp_info, exposed_ips, ovn_ip_rules) # remove extra routes/ips # remove all the leftovers on the list of current ips on dev OVN linux_net.delete_exposed_ips(exposed_ips, constants.OVN_BGP_NIC) # remove all the leftovers on the list of current ip rules for ovn # bridges linux_net.delete_ip_rules(ovn_ip_rules) # remove all the extra rules not needed linux_net.delete_bridge_ip_routes(self.ovn_routing_tables, self.ovn_routing_tables_routes, extra_routes)