def run_lldptool(self, args): '''Function for invoking the lldptool utility''' full_args = ['lldptool'] + args try: utils.execute(full_args, root_helper=self.root_helper) except Exception as e: LOG.error(_LE("Unable to execute %(cmd)s. " "Exception: %(exception)s"), {'cmd': full_args, 'exception': e})
def update_ip_rule(self, ip, mac): """Update a rule associated with given ip and mac.""" rule_no = self._find_rule_no(mac) chain = self._find_chain_name(mac) if not rule_no or not chain: LOG.error(_LE('Failed to update ip rule for %(ip)s %(mac)s'), {'ip': ip, 'mac': mac}) return update_cmd = ['iptables', '-R', '%s' % chain, '%s' % rule_no, '-s', '%s/32' % ip, '-m', 'mac', '--mac-source', '%s' % mac, '-j', 'RETURN'] LOG.debug('Execute command: %s', update_cmd) dsl.execute(update_cmd, self._root_helper, log_output=False)
def program_rtr(self, args, rout_id, namespace=None): """Execute the command against the namespace. """ if namespace is None: namespace = self.find_rtr_namespace(rout_id) if namespace is None: LOG.error("Unable to find namespace for router %s", rout_id) return False final_args = ['ip', 'netns', 'exec', namespace] + args try: utils.execute(final_args, root_helper=self.root_helper) except Exception as e: LOG.error("Unable to execute %(cmd)s. " "Exception: %(exception)s", {'cmd': final_args, 'exception': e}) return False return True
def program_rtr(self, args, rout_id, namespace=None): """Execute the command against the namespace. """ if namespace is None: namespace = self.find_rtr_namespace(rout_id) if namespace is None: LOG.error(_LE("Unable to find namespace for router %s"), rout_id) return False final_args = ['ip', 'netns', 'exec', namespace] + args try: utils.execute(final_args, root_helper=self.root_helper) except Exception as e: LOG.error(_LE("Unable to execute %(cmd)s. " "Exception: %(exception)s"), {'cmd': final_args, 'exception': e}) return False return True
def update_iptables(self): """Update iptables based on information in the rule_info.""" # Read the iptables iptables_cmds = ['iptables-save', '-c'] all_rules = dsl.execute(iptables_cmds, root_helper=self._root_helper, log_output=False) # For each rule in rule_info update the rule if necessary. new_rules = [] is_modified = False for line in all_rules.split('\n'): new_line = line line_content = line.split() # The spoofing rule which includes mac and ip should have # -s cidr/32 option for ip address. Otherwise no rule # will be modified. if '-s' in line_content: tmp_rule_info = list(self.rule_info) for rule in tmp_rule_info: if (rule.mac in line.lower() and rule.chain.lower() in line.lower() and not self._is_ip_in_rule(rule.ip, line_content)): ip_loc = line_content.index('-s') + 1 line_content[ip_loc] = rule.ip + '/32' new_line = ' '.join(line_content) LOG.debug('Modified %(old_rule)s. ' 'New rule is %(new_rule)s.' % ({ 'old_rule': line, 'new_rule': new_line })) is_modified = True new_rules.append(new_line) if is_modified and new_rules: # Updated all the rules. Now commit the new rules. iptables_cmds = ['iptables-restore', '-c'] dsl.execute(iptables_cmds, process_input='\n'.join(new_rules), root_helper=self._root_helper, log_output=False)
def run_vdptool(self, args, oui_args=None): '''Function that runs the vdptool utility''' if oui_args is None: oui_args = [] full_args = ['vdptool'] + args + oui_args try: return utils.execute(full_args, root_helper=self.root_helper) except Exception as e: LOG.error(_LE("Unable to execute %(cmd)s. " "Exception: %(exception)s"), {'cmd': full_args, 'exception': e})
def run_lldptool(self, args): """Function for invoking the lldptool utility. """ full_args = ['lldptool'] + args try: return utils.execute(full_args, root_helper=self.root_helper) except Exception as exc: LOG.error("Unable to execute %(cmd)s. " "Exception: %(exception)s", { 'cmd': full_args, 'exception': str(exc) })
def _find_rule_no(self, mac): """Find rule number associated with a given mac.""" ipt_cmd = ['iptables', '-L', '--line-numbers'] cmdo = dsl.execute(ipt_cmd, self._root_helper, log_output=False) for o in cmdo.split('\n'): if mac in o.lower(): rule_no = o.split()[0] LOG.info(_LI('Found rule %(rule)s for %(mac)s.'), {'rule': rule_no, 'mac': mac}) return rule_no
def _find_chain_name(self, mac): """Find a rule associated with a given mac.""" ipt_cmd = ['iptables', '-t', 'filter', '-S'] cmdo = dsl.execute(ipt_cmd, root_helper=self._root_helper, log_output=False) for o in cmdo.split('\n'): if mac in o.lower(): chain = o.split()[1] LOG.info(_LI('Find %(chain)s for %(mac)s.'), {'chain': chain, 'mac': mac}) return chain
def update_ip_rule(self, ip, mac): """Update a rule associated with given ip and mac.""" rule_no = self._find_rule_no(mac) chain = self._find_chain_name(mac) if not rule_no or not chain: LOG.error(_LE('Failed to update ip rule for %(ip)s %(mac)s'), { 'ip': ip, 'mac': mac }) return update_cmd = [ 'iptables', '-R', '%s' % chain, '%s' % rule_no, '-s', '%s/32' % ip, '-m', 'mac', '--mac-source', '%s' % mac, '-j', 'RETURN' ] LOG.debug('Execute command: %s', update_cmd) dsl.execute(update_cmd, self._root_helper, log_output=False)
def _find_rule_no(self, mac): """Find rule number associated with a given mac.""" ipt_cmd = ['iptables', '-L', '--line-numbers'] cmdo = dsl.execute(ipt_cmd, self._root_helper, log_output=False) for o in cmdo.split('\n'): if mac in o.lower(): rule_no = o.split()[0] LOG.info(_LI('Found rule %(rule)s for %(mac)s.'), { 'rule': rule_no, 'mac': mac }) return rule_no
def update_iptables(self): """Update iptables based on information in the rule_info.""" # Read the iptables iptables_cmds = ['iptables-save', '-c'] all_rules = dsl.execute(iptables_cmds, root_helper=self._root_helper, log_output=False) # For each rule in rule_info update the rule if necessary. new_rules = [] is_modified = False for line in all_rules.split('\n'): new_line = line line_content = line.split() # The spoofing rule which includes mac and ip should have # -s cidr/32 option for ip address. Otherwise no rule # will be modified. if '-s' in line_content: tmp_rule_info = list(self.rule_info) for rule in tmp_rule_info: if (rule.mac in line.lower() and rule.chain.lower() in line.lower() and not self._is_ip_in_rule(rule.ip, line_content)): ip_loc = line_content.index('-s') + 1 line_content[ip_loc] = rule.ip + '/32' new_line = ' '.join(line_content) LOG.debug('Modified %(old_rule)s. ' 'New rule is %(new_rule)s.' % ( {'old_rule': line, 'new_rule': new_line})) is_modified = True new_rules.append(new_line) if is_modified and new_rules: # Updated all the rules. Now commit the new rules. iptables_cmds = ['iptables-restore', '-c'] dsl.execute(iptables_cmds, process_input='\n'.join(new_rules), root_helper=self._root_helper, log_output=False)
def find_rtr_namespace(self, rout_id): """Find the namespace associated with the router. """ if rout_id is None: return None args = ['ip', 'netns', 'list'] try: ns_list = utils.execute(args, root_helper=self.root_helper) except Exception as exc: LOG.error(_LE("Unable to find the namespace list Exception %s"), exc) return None for ns in ns_list.split(): if 'router' in ns and rout_id in ns: return ns
def find_rtr_namespace(self, rout_id): """Find the namespace associated with the router. """ if rout_id is None: return None args = ['ip', 'netns', 'list'] try: ns_list = utils.execute(args, root_helper=self.root_helper) except Exception as exc: LOG.error("Unable to find the namespace list Exception %s", exc) return None for ns in ns_list.split(): if 'router' in ns and rout_id in ns: return ns
def _find_chain_name(self, mac): """Find a rule associated with a given mac.""" ipt_cmd = ['iptables', '-t', 'filter', '-S'] cmdo = dsl.execute(ipt_cmd, root_helper=self._root_helper, log_output=False) for o in cmdo.split('\n'): if mac in o.lower(): chain = o.split()[1] LOG.info(_LI('Find %(chain)s for %(mac)s.'), { 'chain': chain, 'mac': mac }) return chain
def setup_lldpad_ports(self): """Setup the flows for passing LLDP/VDP frames in OVS.""" # Creating the physical bridge and setting up patch ports is done by # Openstack ovs_bridges = ovs_lib.get_bridges(self.root_helper) if self.ext_br not in ovs_bridges or self.integ_br not in ovs_bridges: LOG.error(_LE("Integ or Physical Bridge not configured by" "Openstack")) raise dfae.DfaAgentFailed(reason="Bridge Unavailable") br = ovs_lib.OVSBridge(self.ext_br, root_helper=self.root_helper) self.ext_br_obj = br int_br = ovs_lib.OVSBridge(self.integ_br, root_helper=self.root_helper) self.integ_br_obj = int_br self.phy_peer_port, self.int_peer_port = self.find_interconnect_ports() if self.phy_peer_port is None or self.int_peer_port is None: LOG.error(_LE("Integ or Physical Patch/Veth Ports not " "configured by Openstack")) raise dfae.DfaAgentFailed(reason="Ports Unconfigured") lldp_ovs_veth_str = constants.LLDPAD_OVS_VETH_PORT + self.uplink if len(lldp_ovs_veth_str) > constants.MAX_VETH_NAME: lldp_ovs_veth_str = self.gen_veth_str(constants.LLDPAD_OVS_VETH_PORT, self.uplink) lldp_loc_veth_str = constants.LLDPAD_LOC_VETH_PORT + self.uplink if len(lldp_loc_veth_str) > constants.MAX_VETH_NAME: lldp_loc_veth_str = self.gen_veth_str(constants.LLDPAD_LOC_VETH_PORT, self.uplink) ip_wrapper = ip_lib.IPWrapper() self.delete_vdp_flows() br.delete_port(lldp_ovs_veth_str) if ip_lib.device_exists(lldp_ovs_veth_str): # What about OVS restart cases fixme(padkrish) # IMPORTANT.. The link delete should be done only for non-restart # cases. Otherwise, The MAC address of the veth interface changes # for every delete/create. So, if lldpad has the association sent # already, retriggering it will make the ASSOC appear as coming # from another station and more than one VSI instance will appear # at the Leaf. Deleting the assoc and creating the assoc for new # veth is not optimal. fixme(padkrish) # ip_lib.IPDevice(lldp_ovs_veth_str,self.root_helper).link.delete() ovs_lib.execute(["/sbin/udevadm", "settle", "--timeout=10"]) lldp_loc_veth = ip_wrapper.device(lldp_loc_veth_str) lldp_ovs_veth = ip_wrapper.device(lldp_ovs_veth_str) else: # fixme(padkrish) Due to above reason, do the vethcreate below only # if it doesn't exist and not deleted. lldp_loc_veth, lldp_ovs_veth = ip_wrapper.add_veth(lldp_loc_veth_str, lldp_ovs_veth_str) if not br.port_exists(self.uplink): phy_port_num = br.add_port(self.uplink) else: phy_port_num = br.get_port_ofport(self.uplink) if phy_port_num == cconstants.INVALID_OFPORT: LOG.error(_LE("Uplink port not detected on external bridge")) return False if not br.port_exists(lldp_ovs_veth_str): lldp_ovs_portnum = br.add_port(lldp_ovs_veth) else: lldp_ovs_portnum = br.get_port_ofport(lldp_ovs_veth) if lldp_ovs_portnum == cconstants.INVALID_OFPORT: LOG.error(_LE("lldp veth port not detected on external bridge")) return False lldp_loc_veth.link.set_up() lldp_ovs_veth.link.set_up() # What about OVS restart cases fixme(padkrish) self.program_vdp_flows(lldp_ovs_portnum, phy_port_num) self.phy_peer_port_num = br.get_port_ofport(self.phy_peer_port) self.int_peer_port_num = int_br.get_port_ofport(self.int_peer_port) if self.phy_peer_port_num == cconstants.INVALID_OFPORT or self.int_peer_port_num == cconstants.INVALID_OFPORT: LOG.error( _LE("int or phy peer OF Port not detected on Int or" "Phy Bridge %(phy)s %(int)s"), {"phy": self.phy_peer_port_num, "int": self.int_peer_port_num}, ) return False self.lldpad_info = lldpad.LldpadDriver(lldp_loc_veth_str, self.uplink, self.root_helper) ret = self.lldpad_info.enable_evb() if not ret: LOG.error(_LE("Unable to cfg EVB")) return False self.lldp_veth_port = lldp_loc_veth_str LOG.info(_LI("Setting up lldpad ports complete")) return True
def setup_lldpad_ports(self): '''Setup the flows for passing LLDP/VDP frames in OVS.''' # Creating the physical bridge and setting up patch ports is done by # Openstack ovs_bridges = ovs_lib.get_bridges(self.root_helper) if self.ext_br not in ovs_bridges or self.integ_br not in ovs_bridges: LOG.error( _LE("Integ or Physical Bridge not configured by" "Openstack")) raise dfae.DfaAgentFailed(reason="Bridge Unavailable") br = ovs_lib.OVSBridge(self.ext_br, root_helper=self.root_helper) self.ext_br_obj = br int_br = ovs_lib.OVSBridge(self.integ_br, root_helper=self.root_helper) self.integ_br_obj = int_br self.phy_peer_port, self.int_peer_port = self.find_interconnect_ports() if self.phy_peer_port is None or self.int_peer_port is None: LOG.error( _LE("Integ or Physical Patch/Veth Ports not " "configured by Openstack")) raise dfae.DfaAgentFailed(reason="Ports Unconfigured") lldp_ovs_veth_str = constants.LLDPAD_OVS_VETH_PORT + self.uplink if len(lldp_ovs_veth_str) > constants.MAX_VETH_NAME: lldp_ovs_veth_str = self.gen_veth_str( constants.LLDPAD_OVS_VETH_PORT, self.uplink) lldp_loc_veth_str = constants.LLDPAD_LOC_VETH_PORT + self.uplink if len(lldp_loc_veth_str) > constants.MAX_VETH_NAME: lldp_loc_veth_str = self.gen_veth_str( constants.LLDPAD_LOC_VETH_PORT, self.uplink) ip_wrapper = ip_lib.IPWrapper() self.delete_vdp_flows() br.delete_port(lldp_ovs_veth_str) if ip_lib.device_exists(lldp_ovs_veth_str): # What about OVS restart cases fixme(padkrish) # IMPORTANT.. The link delete should be done only for non-restart # cases. Otherwise, The MAC address of the veth interface changes # for every delete/create. So, if lldpad has the association sent # already, retriggering it will make the ASSOC appear as coming # from another station and more than one VSI instance will appear # at the Leaf. Deleting the assoc and creating the assoc for new # veth is not optimal. fixme(padkrish) # ip_lib.IPDevice(lldp_ovs_veth_str,self.root_helper).link.delete() ovs_lib.execute(['/sbin/udevadm', 'settle', '--timeout=10']) lldp_loc_veth = ip_wrapper.device(lldp_loc_veth_str) lldp_ovs_veth = ip_wrapper.device(lldp_ovs_veth_str) else: # fixme(padkrish) Due to above reason, do the vethcreate below only # if it doesn't exist and not deleted. lldp_loc_veth, lldp_ovs_veth = (ip_wrapper.add_veth( lldp_loc_veth_str, lldp_ovs_veth_str)) if not br.port_exists(self.uplink): phy_port_num = br.add_port(self.uplink) else: phy_port_num = br.get_port_ofport(self.uplink) if phy_port_num == cconstants.INVALID_OFPORT: LOG.error(_LE("Uplink port not detected on external bridge")) return False if not br.port_exists(lldp_ovs_veth_str): lldp_ovs_portnum = br.add_port(lldp_ovs_veth) else: lldp_ovs_portnum = br.get_port_ofport(lldp_ovs_veth) if lldp_ovs_portnum == cconstants.INVALID_OFPORT: LOG.error(_LE("lldp veth port not detected on external bridge")) return False lldp_loc_veth.link.set_up() lldp_ovs_veth.link.set_up() # What about OVS restart cases fixme(padkrish) self.program_vdp_flows(lldp_ovs_portnum, phy_port_num) self.phy_peer_port_num = br.get_port_ofport(self.phy_peer_port) self.int_peer_port_num = int_br.get_port_ofport(self.int_peer_port) if (self.phy_peer_port_num == cconstants.INVALID_OFPORT or self.int_peer_port_num == cconstants.INVALID_OFPORT): LOG.error( _LE("int or phy peer OF Port not detected on Int or" "Phy Bridge %(phy)s %(int)s"), { 'phy': self.phy_peer_port_num, 'int': self.int_peer_port_num }) return False self.lldpad_info = (lldpad.LldpadDriver(lldp_loc_veth_str, self.uplink, self.root_helper)) ret = self.lldpad_info.enable_evb() if not ret: LOG.error(_LE("Unable to cfg EVB")) return False self.lldp_veth_port = lldp_loc_veth_str LOG.info(_LI("Setting up lldpad ports complete")) return True