Exemplo n.º 1
0
def remove_interface(ctx, interface_name):
    """Remove interface related NAT configuration"""
    config_db = ConfigDBConnector()
    config_db.connect()

    if nat_interface_name_is_valid(interface_name) is False:
        ctx.fail(
            "Interface name is invalid. Please enter a  valid interface name!!"
        )

    if interface_name.startswith("Ethernet"):
        interface_table_type = "INTERFACE"
    elif interface_name.startswith("PortChannel"):
        interface_table_type = "PORTCHANNEL_INTERFACE"
    elif interface_name.startswith("Vlan"):
        interface_table_type = "VLAN_INTERFACE"
    elif interface_name.startswith("Loopback"):
        interface_table_type = "LOOPBACK_INTERFACE"

    interface_table_dict = config_db.get_table(interface_table_type)

    if not interface_table_dict or interface_name not in interface_table_dict:
        ctx.fail(
            "Interface table is not present. Ignoring the nat zone configuration"
        )

    config_db.mod_entry(interface_table_type, interface_name,
                        {"nat_zone": "0"})
Exemplo n.º 2
0
def udp_timeout(ctx):
    """Reset NAT UDP timeout configuration to default value (300 seconds)"""
    config_db = ConfigDBConnector()
    config_db.connect()
    seconds = 300

    config_db.mod_entry("NAT_GLOBAL", "Values", {"nat_udp_timeout": seconds})
Exemplo n.º 3
0
def add_interface(ctx, interface_name, nat_zone):
    """Add interface related nat configuration"""

    config_db = ConfigDBConnector()
    config_db.connect()

    if nat_interface_name_is_valid(interface_name) is False:
        ctx.fail(
            "Interface name is invalid. Please enter a  valid interface name!!"
        )

    if interface_name.startswith("Ethernet"):
        interface_table_type = "INTERFACE"
    elif interface_name.startswith("PortChannel"):
        interface_table_type = "PORTCHANNEL_INTERFACE"
    elif interface_name.startswith("Vlan"):
        interface_table_type = "VLAN_INTERFACE"
    elif interface_name.startswith("Loopback"):
        interface_table_type = "LOOPBACK_INTERFACE"

    interface_table_dict = config_db.get_table(interface_table_type)

    if not interface_table_dict or interface_name not in interface_table_dict:
        ctx.fail(
            "Interface table is not present. Please configure ip-address on {} and apply the nat zone !!"
            .format(interface_name))

    config_db.mod_entry(interface_table_type, interface_name,
                        {"nat_zone": nat_zone})
Exemplo n.º 4
0
def _change_bgp_session_status_by_addr(ipaddress, status, verbose):
    """Start up or shut down BGP session by IP address
    """
    verb = 'Starting' if status == 'up' else 'Shutting'
    click.echo("{} {} BGP session with neighbor {}...".format(verb, status, ipaddress))
    config_db = ConfigDBConnector()
    config_db.connect()

    config_db.mod_entry('bgp_neighbor', ipaddress, {'admin_status': status})
Exemplo n.º 5
0
def _change_bgp_session_status_by_addr(ipaddress, status, verbose):
    """Start up or shut down BGP session by IP address
    """
    verb = 'Starting' if status == 'up' else 'Shutting'
    click.echo("{} {} BGP session with neighbor {}...".format(verb, status, ipaddress))
    config_db = ConfigDBConnector()
    config_db.connect()

    config_db.mod_entry('bgp_neighbor', ipaddress, {'admin_status': status})
Exemplo n.º 6
0
def _update_kube_server(field, val):
    config_db = ConfigDBConnector()
    config_db.connect()
    table = "KUBERNETES_MASTER"
    key = "SERVER"
    db_data = Db().get_data(table, key)
    def_data = {"IP": "", "insecure": "False", "disable": "False"}
    for f in def_data:
        if db_data and f in db_data:
            if f == field and db_data[f] != val:
                config_db.mod_entry(table, key, {field: val})
                log.log_info("modify kubernetes server entry {}={}".format(
                    field, val))
        else:
            # Missing field. Set to default or given value
            v = val if f == field else def_data[f]
            config_db.mod_entry(table, key, {f: v})
            log.log_info("set kubernetes server entry {}={}".format(f, v))
Exemplo n.º 7
0
def udp_timeout(ctx, seconds):
    """Set NAT UDP timeout configuration"""
    config_db = ConfigDBConnector()
    config_db.connect()

    config_db.mod_entry("NAT_GLOBAL", "Values", {"nat_udp_timeout": seconds})
Exemplo n.º 8
0
def disable(ctx):
    """Disable the NAT feature """
    config_db = ConfigDBConnector()
    config_db.connect()
    config_db.mod_entry("NAT_GLOBAL", "Values", {"admin_mode": "disabled"})
Exemplo n.º 9
0
        port_ds_entry = {}
        for key in raw_data:
            port_ds_entry = {}
            port_ds_entry["port-number"] = key.replace("PTP_PORT|GLOBAL|", "")
            state_data = db.get_all(db.STATE_DB, key)

            port_ds_entry["port-state"] = port_state_to_str(state_data["port-state"])
            port_ds_list.append(port_ds_entry)
        port_ds_dict['port-ds-list'] = port_ds_list
        api_response_list.append(port_ds_dict)
        api_response['ietf-ptp:instance_list'] = api_response_list
        show_cli_output(sys.argv[3], api_response)
    elif sys.argv[1] == 'patch_ietf_ptp_ptp_instance_list_default_ds_domain_number':
        data = {}
        data['domain-number'] = sys.argv[3]
        config_db.mod_entry(PTP_CLOCK, PTP_GLOBAL, data)
    elif sys.argv[1] == 'patch_ietf_ptp_ptp_instance_list_default_ds_priority1':
        data = {}
        data['priority1'] = sys.argv[3]
        config_db.mod_entry(PTP_CLOCK, PTP_GLOBAL, data)
    elif sys.argv[1] == 'patch_ietf_ptp_ptp_instance_list_default_ds_priority2':
        data = {}
        data['priority2'] = sys.argv[3]
        config_db.mod_entry(PTP_CLOCK, PTP_GLOBAL, data)
    elif sys.argv[1] == 'patch_ietf_ptp_ptp_instance_list_default_ds_two_step_flag':
        data = {}
        if sys.argv[3] == "enable":
            data['two-step-flag'] = '1'
        else:
            data['two-step-flag'] = '0'
        config_db.mod_entry(PTP_CLOCK, PTP_GLOBAL, data)
Exemplo n.º 10
0
def memory(kdump_memory):
    """Set memory allocated for kdump capture kernel"""
    config_db = ConfigDBConnector()
    if config_db is not None:
        config_db.connect()
        config_db.mod_entry("KDUMP", "config", {"memory": kdump_memory})
Exemplo n.º 11
0
class AclLoader(object):

    ACL_TABLE = "ACL_TABLE"
    ACL_RULE = "ACL_RULE"
    ACL_TABLE_TYPE_MIRROR = "MIRROR"
    ACL_TABLE_TYPE_CTRLPLANE = "CTRLPLANE"
    MIRROR_SESSION = "MIRROR_SESSION"
    SESSION_PREFIX = "everflow"

    min_priority = 1
    max_priority = 10000

    ethertype_map = {
        "ETHERTYPE_LLDP": 0x88CC,
        "ETHERTYPE_VLAN": 0x8100,
        "ETHERTYPE_ROCE": 0x8915,
        "ETHERTYPE_ARP": 0x0806,
        "ETHERTYPE_IPV4": 0x0800,
        "ETHERTYPE_IPV6": 0x86DD,
        "ETHERTYPE_MPLS": 0x8847
    }

    ip_protocol_map = {
        "IP_TCP": 6,
        "IP_ICMP": 1,
        "IP_UDP": 17,
        "IP_IGMP": 2,
        "IP_PIM": 103,
        "IP_RSVP": 46,
        "IP_GRE": 47,
        "IP_AUTH": 51,
        "IP_L2TP": 115
    }

    def __init__(self):
        self.yang_acl = None
        self.requested_session = None
        self.current_table = None
        self.tables_db_info = {}
        self.rules_db_info = {}
        self.rules_info = {}
        self.sessions_db_info = {}
        self.configdb = ConfigDBConnector()
        self.configdb.connect()
        self.statedb = SonicV2Connector(host="127.0.0.1")
        self.statedb.connect(self.statedb.STATE_DB)

        self.read_tables_info()
        self.read_rules_info()
        self.read_sessions_info()

    def read_tables_info(self):
        """
        Read ACL tables information from Config DB
        :return:
        """
        self.tables_db_info = self.configdb.get_table(self.ACL_TABLE)

    def get_tables_db_info(self):
        return self.tables_db_info

    def read_rules_info(self):
        """
        Read rules information from Config DB
        :return:
        """
        self.rules_db_info = self.configdb.get_table(self.ACL_RULE)

    def get_rules_db_info(self):
        return self.rules_db_info

    def read_sessions_info(self):
        """
        Read ACL tables information from Config DB
        :return:
        """
        self.sessions_db_info = self.configdb.get_table(self.MIRROR_SESSION)
        for key in self.sessions_db_info.keys():
            state_db_info = self.statedb.get_all(
                self.statedb.STATE_DB, "{}|{}".format(self.MIRROR_SESSION,
                                                      key))
            if state_db_info:
                status = state_db_info.get("status", "inactive")
            else:
                status = "error"
            self.sessions_db_info[key]["status"] = status

    def get_sessions_db_info(self):
        """
        Read mirror session information from Config DB
        :return:
        """
        return self.sessions_db_info

    def get_session_name(self):
        """
        Read mirror session name from Config DB
        :return: Mirror session name
        """
        if self.requested_session:
            return self.requested_session

        for key in self.get_sessions_db_info():
            if key.startswith(self.SESSION_PREFIX):
                return key

        return None

    def set_table_name(self, table_name):
        """
        Set table name to restrict the table to be modified
        :param table_name: Table name
        :return:
        """
        self.current_table = table_name

    def set_session_name(self, session_name):
        """
        Set session name to be used in ACL rule action
        :param session_name: Mirror session name
        :return:
        """
        if session_name not in self.get_sessions_db_info():
            raise AclLoaderException("Session %s does not exist" %
                                     session_name)

        self.requested_session = session_name

    def set_max_priority(self, priority):
        """
        Set rules max priority
        :param priority: Rules max priority
        :return:
        """
        self.max_priority = int(priority)

    def is_table_valid(self, tname):
        return self.tables_db_info.get(tname)

    def is_table_mirror(self, tname):
        """
        Check if ACL table type is ACL_TABLE_TYPE_MIRROR
        :param tname: ACL table name
        :return: True if table type is ACL_TABLE_TYPE_MIRROR else False
        """
        return self.tables_db_info[tname]['type'].upper(
        ) == self.ACL_TABLE_TYPE_MIRROR

    def is_table_control_plane(self, tname):
        """
        Check if ACL table type is ACL_TABLE_TYPE_CTRLPLANE
        :param tname: ACL table name
        :return: True if table type is ACL_TABLE_TYPE_CTRLPLANE else False
        """
        return self.tables_db_info[tname]['type'].upper(
        ) == self.ACL_TABLE_TYPE_CTRLPLANE

    @staticmethod
    def parse_acl_json(filename):
        yang_acl = pybindJSON.load(filename, openconfig_acl, "openconfig_acl")
        # Check pybindJSON parsing
        # pybindJSON.load will silently return an empty json object if input invalid
        with open(filename, 'r') as f:
            plain_json = json.load(f)
            if len(plain_json['acl']['acl-sets']['acl-set']) != len(
                    yang_acl.acl.acl_sets.acl_set):
                raise AclLoaderException("Invalid input file %s" % filename)
        return yang_acl

    def load_rules_from_file(self, filename):
        """
        Load file with ACL rules configuration in openconfig ACL format. Convert rules
        to Config DB schema.
        :param filename: File in openconfig ACL format
        :return:
        """
        self.yang_acl = AclLoader.parse_acl_json(filename)
        self.convert_rules()

    def convert_action(self, table_name, rule_idx, rule):
        rule_props = {}

        if rule.actions.config.forwarding_action == "ACCEPT":
            if self.is_table_control_plane(table_name):
                rule_props["PACKET_ACTION"] = "ACCEPT"
            elif self.is_table_mirror(table_name):
                session_name = self.get_session_name()
                if not session_name:
                    raise AclLoaderException(
                        "Mirroring session does not exist")

                rule_props["MIRROR_ACTION"] = session_name
            else:
                rule_props["PACKET_ACTION"] = "FORWARD"
        elif rule.actions.config.forwarding_action == "DROP":
            rule_props["PACKET_ACTION"] = "DROP"
        elif rule.actions.config.forwarding_action == "REJECT":
            rule_props["PACKET_ACTION"] = "DROP"
        else:
            raise AclLoaderException(
                "Unknown rule action %s in table %s, rule %d" %
                (rule.actions.config.forwarding_action, table_name, rule_idx))

        return rule_props

    def convert_l2(self, table_name, rule_idx, rule):
        rule_props = {}

        if rule.l2.config.ethertype:
            if rule.l2.config.ethertype in self.ethertype_map:
                rule_props["ETHER_TYPE"] = self.ethertype_map[
                    rule.l2.config.ethertype]
            else:
                try:
                    rule_props["ETHER_TYPE"] = int(rule.l2.config.ethertype)
                except:
                    raise AclLoaderException(
                        "Failed to convert ethertype %s table %s rule %s" %
                        (rule.l2.config.ethertype, table_name, rule_idx))

        return rule_props

    def convert_ip(self, table_name, rule_idx, rule):
        rule_props = {}

        if rule.ip.config.protocol:
            if self.ip_protocol_map.has_key(rule.ip.config.protocol):
                rule_props["IP_PROTOCOL"] = self.ip_protocol_map[
                    rule.ip.config.protocol]
            else:
                try:
                    int(rule.ip.config.protocol)
                except:
                    raise AclLoaderException(
                        "Unknown rule protocol %s in table %s, rule %d!" %
                        (rule.ip.config.protocol, table_name, rule_idx))

                rule_props["IP_PROTOCOL"] = rule.ip.config.protocol

        if rule.ip.config.source_ip_address:
            source_ip_address = rule.ip.config.source_ip_address.encode(
                "ascii")
            if ipaddr.IPNetwork(source_ip_address).version == 4:
                rule_props["SRC_IP"] = source_ip_address
            else:
                rule_props["SRC_IPV6"] = source_ip_address

        if rule.ip.config.destination_ip_address:
            destination_ip_address = rule.ip.config.destination_ip_address.encode(
                "ascii")
            if ipaddr.IPNetwork(destination_ip_address).version == 4:
                rule_props["DST_IP"] = destination_ip_address
            else:
                rule_props["DST_IPV6"] = destination_ip_address

        # NOTE: DSCP is available only for MIRROR table
        if self.is_table_mirror(table_name):
            if rule.ip.config.dscp:
                rule_props["DSCP"] = rule.ip.config.dscp

        return rule_props

    def convert_port(self, port):
        """
        Convert port field format from openconfig ACL to Config DB schema
        :param port: String, ACL port number or range in openconfig format
        :return: Tuple, first value is converted port string,
            second value is boolean, True if value is a port range, False
            if it is a single port value
        """
        # OpenConfig port range is of the format "####..####", whereas
        # Config DB format is "####-####"
        if ".." in port:
            return port.replace("..", "-"), True
        else:
            return port, False

    def convert_transport(self, table_name, rule_idx, rule):
        rule_props = {}

        if rule.transport.config.source_port:
            port, is_range = self.convert_port(
                str(rule.transport.config.source_port))
            rule_props[
                "L4_SRC_PORT_RANGE" if is_range else "L4_SRC_PORT"] = port
        if rule.transport.config.destination_port:
            port, is_range = self.convert_port(
                str(rule.transport.config.destination_port))
            rule_props[
                "L4_DST_PORT_RANGE" if is_range else "L4_DST_PORT"] = port

        tcp_flags = 0x00

        for flag in rule.transport.config.tcp_flags:
            if flag == "TCP_FIN":
                tcp_flags |= 0x01
            if flag == "TCP_SYN":
                tcp_flags |= 0x02
            if flag == "TCP_RST":
                tcp_flags |= 0x04
            if flag == "TCP_PSH":
                tcp_flags |= 0x08
            if flag == "TCP_ACK":
                tcp_flags |= 0x10
            if flag == "TCP_URG":
                tcp_flags |= 0x20
            if flag == "TCP_ECE":
                tcp_flags |= 0x40
            if flag == "TCP_CWR":
                tcp_flags |= 0x80

        if tcp_flags:
            rule_props["TCP_FLAGS"] = '0x{:02x}/0x{:02x}'.format(
                tcp_flags, tcp_flags)

        return rule_props

    def convert_input_interface(self, table_name, rule_idx, rule):
        rule_props = {}

        if rule.input_interface.interface_ref.config.interface:
            rule_props[
                "IN_PORTS"] = rule.input_interface.interface_ref.config.interface

        return rule_props

    def convert_rule_to_db_schema(self, table_name, rule):
        """
        Convert rules format from openconfig ACL to Config DB schema
        :param table_name: ACL table name to which rule belong
        :param rule: ACL rule in openconfig format
        :return: dict with Config DB schema
        """
        rule_idx = int(rule.config.sequence_id)
        rule_props = {}
        rule_data = {(table_name, "RULE_" + str(rule_idx)): rule_props}

        rule_props["PRIORITY"] = str(self.max_priority - rule_idx)

        deep_update(rule_props, self.convert_action(table_name, rule_idx,
                                                    rule))
        deep_update(rule_props, self.convert_l2(table_name, rule_idx, rule))
        deep_update(rule_props, self.convert_ip(table_name, rule_idx, rule))
        deep_update(rule_props,
                    self.convert_transport(table_name, rule_idx, rule))
        deep_update(rule_props,
                    self.convert_input_interface(table_name, rule_idx, rule))

        return rule_data

    def deny_rule(self, table_name):
        """
        Create default deny rule in Config DB format
        :param table_name: ACL table name to which rule belong
        :return: dict with Config DB schema
        """
        rule_props = {}
        rule_data = {(table_name, "DEFAULT_RULE"): rule_props}
        rule_props["PRIORITY"] = str(self.min_priority)
        rule_props["ETHER_TYPE"] = str(self.ethertype_map["ETHERTYPE_IPV4"])
        rule_props["PACKET_ACTION"] = "DROP"
        return rule_data

    def convert_rules(self):
        """
        Convert rules in openconfig ACL format to Config DB schema
        :return:
        """
        for acl_set_name in self.yang_acl.acl.acl_sets.acl_set:
            table_name = acl_set_name.replace(" ", "_").replace(
                "-", "_").upper().encode('ascii')
            acl_set = self.yang_acl.acl.acl_sets.acl_set[acl_set_name]

            if not self.is_table_valid(table_name):
                warning("%s table does not exist" % (table_name))
                continue

            if self.current_table is not None and self.current_table != table_name:
                continue

            for acl_entry_name in acl_set.acl_entries.acl_entry:
                acl_entry = acl_set.acl_entries.acl_entry[acl_entry_name]
                try:
                    rule = self.convert_rule_to_db_schema(
                        table_name, acl_entry)
                    deep_update(self.rules_info, rule)
                except AclLoaderException as ex:
                    error("Error processing rule %s: %s. Skipped." %
                          (acl_entry_name, ex))

            if not self.is_table_mirror(table_name):
                deep_update(self.rules_info, self.deny_rule(table_name))

    def full_update(self):
        """
        Perform full update of ACL rules configuration. All existing rules
        will be removed. New rules loaded from file will be installed. If
        the current_table is not empty, only rules within that table will
        be removed and new rules in that table will be installed.
        :return:
        """
        for key in self.rules_db_info.keys():
            if self.current_table is None or self.current_table == key[0]:
                self.configdb.mod_entry(self.ACL_RULE, key, None)

        self.configdb.mod_config({self.ACL_RULE: self.rules_info})

    def incremental_update(self):
        """
        Perform incremental ACL rules configuration update. Get existing rules from
        Config DB. Compare with rules specified in file and perform corresponding
        modifications.
        :return:
        """

        # TODO: Until we test ASIC behavior, we cannot assume that we can insert
        # dataplane ACLs and shift existing ACLs. Therefore, we perform a full
        # update on dataplane ACLs, and only perform an incremental update on
        # control plane ACLs.

        new_rules = set(self.rules_info.iterkeys())
        new_dataplane_rules = set()
        new_controlplane_rules = set()
        current_rules = set(self.rules_db_info.iterkeys())
        current_dataplane_rules = set()
        current_controlplane_rules = set()

        for key in new_rules:
            table_name = key[0]
            if self.tables_db_info[table_name]['type'].upper(
            ) == self.ACL_TABLE_TYPE_CTRLPLANE:
                new_controlplane_rules.add(key)
            else:
                new_dataplane_rules.add(key)

        for key in current_rules:
            table_name = key[0]
            if self.tables_db_info[table_name]['type'].upper(
            ) == self.ACL_TABLE_TYPE_CTRLPLANE:
                current_controlplane_rules.add(key)
            else:
                current_dataplane_rules.add(key)

        # Remove all existing dataplane rules
        for key in current_dataplane_rules:
            self.configdb.mod_entry(self.ACL_RULE, key, None)

        # Add all new dataplane rules
        for key in new_dataplane_rules:
            self.configdb.mod_entry(self.ACL_RULE, key, self.rules_info[key])

        added_controlplane_rules = new_controlplane_rules.difference(
            current_controlplane_rules)
        removed_controlplane_rules = current_controlplane_rules.difference(
            new_controlplane_rules)
        existing_controlplane_rules = new_rules.intersection(
            current_controlplane_rules)

        for key in added_controlplane_rules:
            self.configdb.mod_entry(self.ACL_RULE, key, self.rules_info[key])

        for key in removed_controlplane_rules:
            self.configdb.mod_entry(self.ACL_RULE, key, None)

        for key in existing_controlplane_rules:
            if cmp(self.rules_info[key], self.rules_db_info[key]) != 0:
                self.configdb.set_entry(self.ACL_RULE, key,
                                        self.rules_info[key])

    def delete(self, table=None, rule=None):
        """
        :param table:
        :param rule:
        :return:
        """
        for key in self.rules_db_info.iterkeys():
            if not table or table == key[0]:
                if not rule or rule == key[1]:
                    self.configdb.set_entry(self.ACL_RULE, key, None)

    def show_table(self, table_name):
        """
        Show ACL table configuration.
        :param table_name: Optional. ACL table name. Filter tables by specified name.
        :return:
        """
        header = ("Name", "Type", "Binding", "Description")

        data = []
        for key, val in self.get_tables_db_info().iteritems():
            if table_name and key != table_name:
                continue

            if val["type"] == AclLoader.ACL_TABLE_TYPE_CTRLPLANE:
                services = natsorted(val["services"])
                data.append(
                    [key, val["type"], services[0], val["policy_desc"]])

                if len(services) > 1:
                    for service in services[1:]:
                        data.append(["", "", service, ""])
            else:
                if not val["ports"]:
                    data.append([key, val["type"], "", val["policy_desc"]])
                else:
                    ports = natsorted(val["ports"])
                    data.append(
                        [key, val["type"], ports[0], val["policy_desc"]])

                    if len(ports) > 1:
                        for port in ports[1:]:
                            data.append(["", "", port, ""])

        print(
            tabulate.tabulate(data,
                              headers=header,
                              tablefmt="simple",
                              missingval=""))

    def show_session(self, session_name):
        """
        Show mirror session configuration.
        :param session_name: Optional. Mirror session name. Filter sessions by specified name.
        :return:
        """
        header = ("Name", "Status", "SRC IP", "DST IP", "GRE", "DSCP", "TTL",
                  "Queue")

        data = []
        for key, val in self.get_sessions_db_info().iteritems():
            if session_name and key != session_name:
                continue

            data.append([
                key, val["status"], val["src_ip"], val["dst_ip"],
                val.get("gre_type", ""),
                val.get("dscp", ""),
                val.get("ttl", ""),
                val.get("queue", "")
            ])

        print(
            tabulate.tabulate(data,
                              headers=header,
                              tablefmt="simple",
                              missingval=""))

    def show_rule(self, table_name, rule_id):
        """
        Show ACL rules configuration.
        :param table_name: Optional. ACL table name. Filter rules by specified table name.
        :param rule_id: Optional. ACL rule name. Filter rule by specified rule name.
        :return:
        """
        header = ("Table", "Rule", "Priority", "Action", "Match")

        ignore_list = ["PRIORITY", "PACKET_ACTION", "MIRROR_ACTION"]

        raw_data = []
        for (tname, rid), val in self.get_rules_db_info().iteritems():

            if table_name and table_name != tname:
                continue

            if rule_id and rule_id != rid:
                continue

            priority = val["PRIORITY"]

            action = ""
            if "PACKET_ACTION" in val:
                action = val["PACKET_ACTION"]
            elif "MIRROR_ACTION" in val:
                action = "MIRROR: %s" % val["MIRROR_ACTION"]
            else:
                continue

            matches = [
                "%s: %s" % (k, v) for k, v in val.iteritems()
                if k not in ignore_list
            ]

            matches.sort()

            rule_data = [[tname, rid, priority, action, matches[0]]]
            if len(matches) > 1:
                for m in matches[1:]:
                    rule_data.append(["", "", "", "", m])

            raw_data.append([priority, rule_data])

        def cmp_rules(a, b):
            return cmp(a[0], b[0])

        raw_data.sort(cmp_rules)
        raw_data.reverse()

        data = []
        for _, d in raw_data:
            data += d

        print(
            tabulate.tabulate(data,
                              headers=header,
                              tablefmt="simple",
                              missingval=""))
Exemplo n.º 12
0
class AclLoader(object):

    ACL_TABLE = "ACL_TABLE"
    ACL_RULE = "ACL_RULE"
    MIRROR_SESSION = "MIRROR_SESSION"
    SESSION_PREFIX = "everflow"

    min_priority = 1
    max_priority = 10000

    ethertype_map = {
        "ETHERTYPE_LLDP": 0x88CC,
        "ETHERTYPE_VLAN": 0x8100,
        "ETHERTYPE_ROCE": 0x8915,
        "ETHERTYPE_ARP": 0x0806,
        "ETHERTYPE_IPV4": 0x0800,
        "ETHERTYPE_IPV6": 0x86DD,
        "ETHERTYPE_MPLS": 0x8847
    }

    ip_protocol_map = {
        "IP_TCP": 6,
        "IP_ICMP": 1,
        "IP_UDP": 17,
        "IP_IGMP": 2,
        "IP_PIM": 103,
        "IP_RSVP": 46,
        "IP_GRE": 47,
        "IP_AUTH": 51,
        "IP_L2TP": 115
    }

    def __init__(self):
        self.yang_acl = None
        self.requested_session = None
        self.tables_db_info = {}
        self.rules_db_info = {}
        self.rules_info = {}
        self.sessions_db_info = {}
        self.configdb = ConfigDBConnector()
        self.configdb.connect()

        self.read_tables_info()
        self.read_rules_info()
        self.read_sessions_info()

    def read_tables_info(self):
        """
        Read ACL tables information from Config DB
        :return:
        """
        self.tables_db_info = self.configdb.get_table(self.ACL_TABLE)

    def get_tables_db_info(self):
        return self.tables_db_info

    def read_rules_info(self):
        """
        Read rules information from Config DB
        :return:
        """
        self.rules_db_info = self.configdb.get_table(self.ACL_RULE)

    def get_rules_db_info(self):
        return self.rules_db_info

    def read_sessions_info(self):
        """
        Read ACL tables information from Config DB
        :return:
        """
        self.sessions_db_info = self.configdb.get_table(self.MIRROR_SESSION)

    def get_sessions_db_info(self):
        """
        Read mirror session information from Config DB
        :return:
        """
        return self.sessions_db_info

    def get_session_name(self):
        """
        Read mirror session name from Config DB
        :return: Mirror session name
        """
        if self.requested_session:
            return self.requested_session

        for key in self.get_sessions_db_info():
            if key.startswith(self.SESSION_PREFIX):
                return key

        return None

    def set_session_name(self, session_name):
        """
        Set session name to se used in ACL rule action.
        :param session_name: Mirror session name
        """
        if session_name not in self.get_sessions_db_info():
            raise AclLoaderException("Session %s does not exist" % session_name)

        self.requested_session = session_name

    def set_max_priority(self, priority):
        """
        Set rules max priority
        :param priority: Rules max priority
        :return:
        """
        self.max_priority = int(priority)

    def is_table_valid(self, tname):
        return self.tables_db_info.get(tname)

    def is_table_mirror(self, tname):
        """
        Check if ACL table type is MIRROR
        :param tname: ACL table name
        :return: True if table type is MIRROR else False
        """
        return self.tables_db_info[tname]['type'].upper() == "MIRROR"

    def load_rules_from_file(self, filename):
        """
        Load file with ACL rules configuration in openconfig ACL format. Convert rules
        to Config DB schema.
        :param filename: File in openconfig ACL format
        :return:
        """
        self.yang_acl = pybindJSON.load(filename, openconfig_acl, "openconfig_acl")
        self.convert_rules()

    def convert_action(self, table_name, rule_idx, rule):
        rule_props = {}

        if rule.actions.config.forwarding_action == "ACCEPT":
            if self.is_table_mirror(table_name):
                session_name = self.get_session_name()
                if not session_name:
                    raise AclLoaderException("Mirroring session does not exist")

                rule_props["MIRROR_ACTION"] = session_name
            else:
                rule_props["PACKET_ACTION"] = "FORWARD"
        elif rule.actions.config.forwarding_action == "DROP":
            rule_props["PACKET_ACTION"] = "DROP"
        elif rule.actions.config.forwarding_action == "REJECT":
            rule_props["PACKET_ACTION"] = "DROP"
        else:
            raise AclLoaderException("Unknown rule action %s in table %s, rule %d" % (
                rule.actions.config.forwarding_action, table_name, rule_idx))

        return rule_props

    def convert_l2(self, table_name, rule_idx, rule):
        rule_props = {}

        if rule.l2.config.ethertype:
            if rule.l2.config.ethertype in self.ethertype_map:
                rule_props["ETHER_TYPE"] = self.ethertype_map[rule.l2.config.ethertype]
            else:
                try:
                    rule_props["ETHER_TYPE"] = int(rule.l2.config.ethertype)
                except:
                    raise AclLoaderException("Failed to convert ethertype %s table %s rule %s" % (
                        rule.l2.config.ethertype, table_name, rule_idx))

        return rule_props

    def convert_ipv4(self, table_name, rule_idx, rule):
        rule_props = {}

        if rule.ip.config.protocol:
            if self.ip_protocol_map.has_key(rule.ip.config.protocol):
                rule_props["IP_PROTOCOL"] = self.ip_protocol_map[rule.ip.config.protocol]
            else:
                try:
                    int(rule.ip.config.protocol)
                except:
                    raise AclLoaderException("Unknown rule protocol %s in table %s, rule %d!" % (
                        rule.ip.config.protocol, table_name, rule_idx))

                rule_props["IP_PROTOCOL"] = rule.ip.config.protocol

        if rule.ip.config.source_ip_address:
            rule_props["SRC_IP"] = rule.ip.config.source_ip_address

        if rule.ip.config.destination_ip_address:
            rule_props["DST_IP"] = rule.ip.config.destination_ip_address

        # NOTE: DSCP is available only for MIRROR table
        if self.is_table_mirror(table_name):
            if rule.ip.config.dscp:
                rule_props["DSCP"] = rule.ip.config.dscp

        return rule_props

    def convert_port(self, port):
        if ".." in port:
            return  port.replace("..", "-"), True
        else:
            return port, False

    def convert_transport(self,  table_name, rule_idx, rule):
        rule_props = {}

        if rule.transport.config.source_port:
            port, is_range = self.convert_port(str(rule.transport.config.source_port))
            rule_props["L4_SRC_PORT_RANGE" if is_range else "L4_SRC_PORT"] = port
        if rule.transport.config.destination_port:
            port, is_range = self.convert_port(str(rule.transport.config.destination_port))
            rule_props["L4_DST_PORT_RANGE" if is_range else "L4_DST_PORT"] = port

        tcp_flags = 0x00

        for flag in rule.transport.config.tcp_flags:
            if flag == "TCP_FIN":
                tcp_flags = tcp_flags | 0x01
            if flag == "TCP_SYN":
                tcp_flags = tcp_flags | 0x02
            if flag == "TCP_RST":
                tcp_flags = tcp_flags | 0x04
            if flag == "TCP_PSH":
                tcp_flags = tcp_flags | 0x08
            if flag == "TCP_ACK":
                tcp_flags = tcp_flags | 0x10
            if flag == "TCP_URG":
                tcp_flags = tcp_flags | 0x20
            if flag == "TCP_ECE":
                tcp_flags = tcp_flags | 0x40
            if flag == "TCP_CWR":
                tcp_flags = tcp_flags | 0x80

        if tcp_flags:
            rule_props["TCP_FLAGS"] = '0x{:02x}/0x{:02x}'.format(tcp_flags, tcp_flags)

        return rule_props

    def convert_rule_to_db_schema(self, table_name, rule):
        """
        Convert rules format from openconfig ACL to Config DB schema
        :param table_name: ACL table name to which rule belong
        :param rule: ACL rule in openconfig format
        :return: dict with Config DB schema
        """
        rule_idx = int(rule.config.sequence_id)
        rule_props = {}
        rule_data = {(table_name, "RULE_" + str(rule_idx)): rule_props}

        rule_props["PRIORITY"] = self.max_priority - rule_idx

        deep_update(rule_props, self.convert_action(table_name, rule_idx, rule))
        deep_update(rule_props, self.convert_l2(table_name, rule_idx, rule))
        deep_update(rule_props, self.convert_ipv4(table_name, rule_idx, rule))
        deep_update(rule_props, self.convert_transport(table_name, rule_idx, rule))

        return rule_data

    def deny_rule(self, table_name):
        """
        Create default deny rule in Config DB format
        :param table_name: ACL table name to which rule belong
        :return: dict with Config DB schema
        """
        rule_props = {}
        rule_data = {(table_name, "DEFAULT_RULE"): rule_props}
        rule_props["PRIORITY"] = self.min_priority
        rule_props["ETHER_TYPE"] = "0x0800"
        rule_props["PACKET_ACTION"] = "DROP"
        return rule_data

    def convert_rules(self):
        """
        Convert rules in openconfig ACL format to Config DB schema
        :return:
        """
        for acl_set_name in self.yang_acl.acl.acl_sets.acl_set:
            table_name = acl_set_name.replace(" ", "_").replace("-", "_").upper()
            acl_set = self.yang_acl.acl.acl_sets.acl_set[acl_set_name]

            if not self.is_table_valid(table_name):
                warning("%s table does not exist" % (table_name))
                continue

            for acl_entry_name in acl_set.acl_entries.acl_entry:
                acl_entry = acl_set.acl_entries.acl_entry[acl_entry_name]
                rule = self.convert_rule_to_db_schema(table_name, acl_entry)
                deep_update(self.rules_info, rule)

            if not self.is_table_mirror(table_name):
                deep_update(self.rules_info, self.deny_rule(table_name))

    def full_update(self):
        """
        Perform full update of ACL rules configuration. All existing rules
        will be removed. New rules loaded from file will be installed.
        :return:
        """
        for key in self.rules_db_info.keys():
            self.configdb.mod_entry(self.ACL_RULE, key, None)

        self.configdb.mod_config({self.ACL_RULE: self.rules_info})

    def incremental_update(self):
        """
        Perform incremental ACL rules configuration update. Get existing rules from
        Config DB. Compare with rules specified in file and perform corresponding
        modifications.
        :return:
        """
        new_rules = set(self.rules_info.iterkeys())
        current_rules = set(self.rules_db_info.iterkeys())

        added_rules = new_rules.difference(current_rules)
        removed_rules = current_rules.difference(new_rules)
        existing_rules = new_rules.intersection(current_rules)

        for key in removed_rules:
            self.configdb.mod_entry(self.ACL_RULE, key, None)

        for key in added_rules:
            self.configdb.mod_entry(self.ACL_RULE, key, self.rules_info[key])

        for key in existing_rules:
            if cmp(self.rules_info[key], self.rules_db_info[key]):
                self.configdb.mod_entry(self.ACL_RULE, key, None)
                self.configdb.mod_entry(self.ACL_RULE, key, self.rules_info[key])

    def show_table(self, table_name):
        """
        Show ACL table configuration.
        :param table_name: Optional. ACL table name. Filter tables by specified name.
        :return:
        """
        header = ("Name", "Type", "Ports", "Description")

        data = []
        for key, val in self.get_tables_db_info().iteritems():
            if table_name and key != table_name:
                continue

            if not val["ports"]:
                data.append([key, val["type"], "", val["policy_desc"]])
            else:
                ports = natsorted(val["ports"])
                data.append([key, val["type"], ports[0], val["policy_desc"]])

                if len(ports) > 1:
                    for port in ports[1:]:
                        data.append(["", "", port, ""])

        print(tabulate.tabulate(data, headers=header, tablefmt="simple", missingval=""))

    def show_session(self, session_name):
        """
        Show mirror session configuration.
        :param session_name: Optional. Mirror session name. Filter sessions by specified name.
        :return:
        """
        header = ("Name", "SRC IP", "DST IP", "GRE", "DSCP", "TTL", "Queue")

        data = []
        for key, val in self.get_sessions_db_info().iteritems():
            if session_name and key != session_name:
                continue

            data.append([key, val["src_ip"], val["dst_ip"],
                         val.get("gre_type", ""), val.get("dscp", ""),
                         val.get("ttl", ""), val.get("queue", "")])

        print(tabulate.tabulate(data, headers=header, tablefmt="simple", missingval=""))

    def show_rule(self, table_name, rule_id):
        """
        Show ACL rules configuration.
        :param table_name: Optional. ACL table name. Filter rules by specified table name.
        :param rule_id: Optional. ACL rule name. Filter rule by specified rule name.
        :return:
        """
        header = ("Rule ID", "Table Name", "Priority", "Action", "Match")

        ignore_list = ["PRIORITY", "PACKET_ACTION", "MIRROR_ACTION"]

        raw_data = []
        for (tname, rid), val in self.get_rules_db_info().iteritems():

            if table_name and table_name != tname:
                continue

            if rule_id and rule_id != rid:
                continue

            priority = val["PRIORITY"]

            action = ""
            if "PACKET_ACTION" in val:
                action = val["PACKET_ACTION"]
            elif "MIRROR_ACTION" in val:
                action = "MIRROR: %s" % val["MIRROR_ACTION"]
            else:
                continue

            matches = ["%s: %s" % (k, v) for k, v in val.iteritems() if k not in ignore_list]

            matches.sort()

            rule_data = [[tname, rid, priority, action, matches[0]]]
            if len(matches) > 1:
                for m in matches[1:]:
                    rule_data.append(["", "", "", "", m])

            raw_data.append([priority, rule_data])

        def cmp_rules(a, b):
            return cmp(a[0], b[0])

        raw_data.sort(cmp_rules)
        raw_data.reverse()

        data = []
        for _, d in raw_data:
            data += d

        print(tabulate.tabulate(data, headers=header, tablefmt="simple", missingval=""))
class DropMon(object):
    def __init__(self):
        # connect CONFIG DB
        self.config_db = ConfigDBConnector()
        self.config_db.connect()

        # connect COUNTERS_DB
        self.counters_db = ConfigDBConnector()
        self.counters_db.db_connect('COUNTERS_DB')

        # connect APPL DB
        self.app_db = ConfigDBConnector()
        self.app_db.db_connect('APPL_DB')

    def config_drop_mon(self, args):
        self.config_db.mod_entry(
            TAM_DROP_MONITOR_FLOW_TABLE, args.flowname, {
                'acl-table': args.acl_table,
                'acl-rule': args.acl_rule,
                'collector': args.dropcollector,
                'sample': args.dropsample
            })
        return

    def config_drop_mon_aging(self, args):
        self.config_db.mod_entry(TAM_DROP_MONITOR_AGING_INTERVAL_TABLE,
                                 "aging",
                                 {'aging-interval': args.aginginterval})
        return

    def config_drop_mon_sample(self, args):
        self.config_db.mod_entry(SAMPLE_RATE_TABLE, args.samplename,
                                 {'sampling-rate': args.rate})
        return

    def clear_single_drop_mon_flow(self, key):
        entry = self.config_db.get_entry(TAM_DROP_MONITOR_FLOW_TABLE, key)
        if entry:
            self.config_db.set_entry(TAM_DROP_MONITOR_FLOW_TABLE, key, None)
        else:
            return False
        return

    def clear_drop_mon_flow(self, args):
        key = args.flowname
        if key == "all":
            # Get all the flow keys
            table_data = self.config_db.get_keys(TAM_DROP_MONITOR_FLOW_TABLE)
            if not table_data:
                return True
            # Clear each flow key
            for key in table_data:
                self.clear_single_drop_mon_flow(key)
        else:
            # Clear the specified flow entry
            self.clear_single_drop_mon_flow(key)

        return

    def clear_drop_mon_sample(self, args):
        key = args.samplename
        entry = self.config_db.get_entry(SAMPLE_RATE_TABLE, key)
        if entry:
            self.config_db.set_entry(SAMPLE_RATE_TABLE, key, None)
        else:
            print "Entry Not Found"
            return False
        return

    def clear_drop_mon_aging_int(self, args):
        key = "aging"
        entry = self.config_db.get_entry(TAM_DROP_MONITOR_AGING_INTERVAL_TABLE,
                                         key)
        if entry:
            self.config_db.set_entry(TAM_DROP_MONITOR_AGING_INTERVAL_TABLE,
                                     key, None)
        else:
            return False
        return

    def show_flow(self, args):
        self.get_print_all_dropmon_flows(args.flowname)
        return

    def get_dropmon_flow_stat(self, flowname):
        api_response_stat = {}
        api_response, entryfound = self.get_dropmon_flow_info(flowname)
        api_response_stat['flow-name'] = flowname
        if entryfound is not None:
            for k in api_response:
                if k == "ietf-ts:each-flow-data":
                    acl_rule = api_response['ietf-ts:each-flow-data'][
                        'acl-rule']
                    acl_table = api_response['ietf-ts:each-flow-data'][
                        'acl-table']
                    api_response_stat['rule-name'] = acl_rule
                    api_response_stat['table-name'] = acl_table

        acl_rule_keys = self.config_db.get_keys(ACL_RULE_TABLE_PREFIX)
        for acl_rule_key in acl_rule_keys:
            if acl_rule_key[1] == acl_rule:
                acl_counter_key = 'COUNTERS:' + acl_rule_key[
                    0] + ':' + acl_rule_key[1]
                raw_dropmon_stats = self.counters_db.get_all(
                    self.counters_db.COUNTERS_DB, acl_counter_key)
                api_response_stat['ietf-ts:dropmon-stats'] = raw_ifa_stats

        return api_response_stat, entryfound

    def get_print_all_dropmon_stats(self, name):
        stat_dict = {}
        stat_list = []
        if name != 'all':
            api_response, entryfound = self.get_dropmon_flow_stat(name)
            if entryfound is not None:
                stat_list.append(api_response)
        else:
            table_data = self.config_db.get_keys(TAM_DROP_MONITOR_FLOW_TABLE)
            # Get data for all keys
            for k in table_data:
                api_each_stat_response, entryfound = self.get_dropmon_flow_stat(
                    k)
                if entryfound is not None:
                    stat_list.append(api_each_stat_response)

        stat_dict['stat-list'] = stat_list
        show_cli_output("show_statistics_flow.j2", stat_dict)
        return

    def show_statistics(self, args):
        self.get_print_all_dropmon_stats(args.flowname)
        return

    def show_aging_interval(self, args):
        key = "aging"
        entry = self.config_db.get_entry(TAM_DROP_MONITOR_AGING_INTERVAL_TABLE,
                                         key)
        if entry:
            print "Aging interval : {}".format(entry['aging-interval'])
        return

    def show_sample(self, args):
        self.get_print_all_sample(args.samplename)
        return

    def get_dropmon_flow_info(self, k):
        flow_data = {}
        flow_data['acl-table-name'] = ''
        flow_data['sampling-rate'] = ''
        flow_data['collector'] = ''

        api_response = {}
        key = TAM_DROP_MONITOR_FLOW_TABLE + '|' + k
        raw_flow_data = self.config_db.get_all(self.config_db.CONFIG_DB, key)
        if raw_flow_data:
            sample = raw_flow_data['sample']
            rate = self.config_db.get_entry(SAMPLE_RATE_TABLE, sample)
            raw_flow_data['sample'] = rate['sampling-rate']
        api_response['ietf-ts:flow-key'] = k
        api_response['ietf-ts:each-flow-data'] = raw_flow_data
        return api_response, raw_flow_data

    def get_print_all_dropmon_flows(self, name):
        flow_dict = {}
        flow_list = []
        if name != 'all':
            api_response, entryfound = self.get_dropmon_flow_info(name)
            if entryfound is not None:
                flow_list.append(api_response)
        else:
            table_data = self.config_db.get_keys(TAM_DROP_MONITOR_FLOW_TABLE)
            # Get data for all keys
            for k in table_data:
                api_each_flow_response, entryfound = self.get_dropmon_flow_info(
                    k)
                if entryfound is not None:
                    flow_list.append(api_each_flow_response)

        flow_dict['flow-list'] = flow_list
        show_cli_output("show_drop_monitor_flow.j2", flow_dict)
        return

    def get_sample_info(self, k):
        sample_data = {}
        sample_data['sampling-rate'] = ''

        api_response = {}
        key = SAMPLE_RATE_TABLE + '|' + k
        raw_sample_data = self.config_db.get_all(self.config_db.CONFIG_DB, key)
        api_response['ietf-ts:sample-key'] = k
        api_response['ietf-ts:each-sample-data'] = raw_sample_data
        return api_response, raw_sample_data

    def get_print_all_sample(self, name):
        sample_dict = {}
        sample_list = []
        if name != 'all':
            api_response, entryfound = self.get_sample_info(name)
            if entryfound is not None:
                sample_list.append(api_response)
        else:
            table_data = self.config_db.get_keys(SAMPLE_RATE_TABLE)
            # Get data for all keys
            for k in table_data:
                api_each_flow_response, entryfound = self.get_sample_info(k)
                if entryfound is not None:
                    sample_list.append(api_each_flow_response)

        sample_dict['sample-list'] = sample_list
        show_cli_output("show_sample.j2", sample_dict)
        return
Exemplo n.º 14
0
def add_table_kv(table, entry, key, val):
    config_db = ConfigDBConnector()
    config_db.connect()
    config_db.mod_entry(table, entry, {key:val})
Exemplo n.º 15
0
class Ts(object):
    def __init__(self):
        # connect CONFIG DB
        self.config_db = ConfigDBConnector()
        self.config_db.connect()

        # connect COUNTER DB
        self.counters_db = ConfigDBConnector()
        self.counters_db.db_connect('COUNTERS_DB')

        # connect APPL DB
        self.app_db = ConfigDBConnector()
        self.app_db.db_connect('APPL_DB')

    def config_enable(self, args):
        """ Enable ifa """
        key = 'feature'
        self.config_db.set_entry(TAM_INT_IFA_TS_FEATURE_TABLE_PREFIX, key,
                                 {'enable': "true"})
        print "Enabled IFA"

        return

    def config_disable(self, args):
        """ Disable ifa """
        key = 'feature'
        self.config_db.set_entry(TAM_INT_IFA_TS_FEATURE_TABLE_PREFIX, key,
                                 {'enable': "false"})
        print "Disabled IFA"

        return

    def config_flow(self, args):
        key = TAM_INT_IFA_FLOW_TS_TABLE_PREFIX + '|' + args.flowname
        entry = self.config_db.get_all(self.config_db.CONFIG_DB, key)
        if entry is None:
            if args.acl_table_name:
                self.config_db.mod_entry(
                    TAM_INT_IFA_FLOW_TS_TABLE_PREFIX, args.flowname,
                    {'acl-table-name': args.acl_table_name})
            if args.acl_rule_name:
                self.config_db.mod_entry(TAM_INT_IFA_FLOW_TS_TABLE_PREFIX,
                                         args.flowname,
                                         {'acl-rule-name': args.acl_rule_name})
        else:
            print "Entry Already Exists"
            return False
        return

    def clear_each_flow(self, flowname):
        entry = self.config_db.get_entry(TAM_INT_IFA_FLOW_TS_TABLE_PREFIX,
                                         flowname)
        if entry:
            self.config_db.set_entry(TAM_INT_IFA_FLOW_TS_TABLE_PREFIX,
                                     flowname, None)
        else:
            print "Entry Not Found"
            return False

        return

    def clear_flow(self, args):
        key = args.flowname
        if key == "all":
            # Get all the flow keys
            table_data = self.config_db.get_keys(
                TAM_INT_IFA_FLOW_TS_TABLE_PREFIX)
            if not table_data:
                return True
            # Clear each flow key
            for key in table_data:
                self.clear_each_flow(key)
        else:
            # Clear the specified flow entry
            self.clear_each_flow(key)

        return

    def show_flow(self, args):
        self.get_print_all_ifa_flows(args.flowname)
        return

    def show_status(self):
        # Get data for all keys
        flowtable_keys = self.config_db.get_keys(
            TAM_INT_IFA_FLOW_TS_TABLE_PREFIX)

        api_response = {}
        key = TAM_INT_IFA_TS_FEATURE_TABLE_PREFIX + '|' + 'feature'
        raw_data_feature = self.config_db.get_all(self.config_db.CONFIG_DB,
                                                  key)
        api_response['ietf-ts:feature-data'] = raw_data_feature
        api_inner_response = {}
        api_inner_response["num-of-flows"] = len(flowtable_keys)
        api_response['ietf-ts:num-of-flows'] = api_inner_response
        key = TAM_DEVICE_TABLE_PREFIX + '|' + 'device'
        raw_data_device = self.config_db.get_all(self.config_db.CONFIG_DB, key)
        api_response['ietf-ts:device-data'] = raw_data_device
        show_cli_output("show_status.j2", api_response)

        return

    def get_ifa_flow_stat(self, flowname):
        api_response_stat = {}
        api_response, entryfound = self.get_ifa_flow_info(flowname)
        api_response_stat['flow-name'] = flowname
        if entryfound is not None:
            for k in api_response:
                if k == "ietf-ts:each-flow-data":
                    acl_rule_name = api_response['ietf-ts:each-flow-data'][
                        'acl-rule-name']
                    acl_table_name = api_response['ietf-ts:each-flow-data'][
                        'acl-table-name']
                    api_response_stat['rule-name'] = acl_rule_name
                    api_response_stat['table-name'] = acl_table_name

        acl_rule_keys = self.config_db.get_keys(ACL_RULE_TABLE_PREFIX)
        for acl_rule_key in acl_rule_keys:
            if acl_rule_key[1] == acl_rule_name:
                acl_counter_key = 'COUNTERS:' + acl_rule_key[
                    0] + ':' + acl_rule_key[1]
                raw_ifa_stats = self.counters_db.get_all(
                    self.counters_db.COUNTERS_DB, acl_counter_key)
                api_response_stat['ietf-ts:ifa-stats'] = raw_ifa_stats

        return api_response_stat, entryfound

    def get_print_all_ifa_stats(self, name):
        stat_dict = {}
        stat_list = []
        if name != 'all':
            api_response, entryfound = self.get_ifa_flow_stat(name)
            if entryfound is not None:
                stat_list.append(api_response)
        else:
            table_data = self.config_db.get_keys(
                TAM_INT_IFA_FLOW_TS_TABLE_PREFIX)
            # Get data for all keys
            for k in table_data:
                api_each_stat_response, entryfound = self.get_ifa_flow_stat(k)
                if entryfound is not None:
                    stat_list.append(api_each_stat_response)

        stat_dict['stat-list'] = stat_list
        show_cli_output("show_statistics_flow.j2", stat_dict)
        return

    def show_statistics(self, args):
        self.get_print_all_ifa_stats(args.flowname)
        return

    def get_ifa_flow_info(self, k):
        flow_data = {}
        flow_data['acl-table-name'] = ''
        flow_data['sampling-rate'] = ''
        flow_data['collector'] = ''

        api_response = {}
        key = TAM_INT_IFA_FLOW_TS_TABLE_PREFIX + '|' + k
        raw_flow_data = self.config_db.get_all(self.config_db.CONFIG_DB, key)
        api_response['ietf-ts:flow-key'] = k
        api_response['ietf-ts:each-flow-data'] = raw_flow_data
        return api_response, raw_flow_data

    def get_print_all_ifa_flows(self, name):
        flow_dict = {}
        flow_list = []
        if name != 'all':
            api_response, entryfound = self.get_ifa_flow_info(name)
            if entryfound is not None:
                flow_list.append(api_response)
        else:
            table_data = self.config_db.get_keys(
                TAM_INT_IFA_FLOW_TS_TABLE_PREFIX)
            # Get data for all keys
            for k in table_data:
                api_each_flow_response, entryfound = self.get_ifa_flow_info(k)
                if entryfound is not None:
                    flow_list.append(api_each_flow_response)

        flow_dict['flow-list'] = flow_list
        show_cli_output("show_flow.j2", flow_dict)
        return

    def get_ifa_supported_info(self):
        key = 'TAM_INT_IFA_TS_FEATURE_TABLE|feature'
        data = self.config_db.get_all(self.config_db.CONFIG_DB, key)

        if data is None:
            return

        if data['enable'] == "true":
            print "TAM INT IFA TS Supported - True"
            return True
        elif data['enable'] == "false":
            print "TAM INT IFA TS Supported - False "
            return False

        return

    def get_ifa_enabled_info(self):
        print "In get_ifa_enabled_info"
        key = 'SWITCH_TABLE:switch'
        data = self.app_db.get(self.app_db.APPL_DB, key, 'ifa_enabled')

        if data and data == 'True':
            return True

        return True
Exemplo n.º 16
0
def add_table_kv(table, entry, key, val):
    config_db = ConfigDBConnector()
    config_db.connect()
    config_db.mod_entry(table, entry, {key: val})
Exemplo n.º 17
0
def enable():
    """Enable kdump operation"""
    config_db = ConfigDBConnector()
    if config_db is not None:
        config_db.connect()
        config_db.mod_entry("KDUMP", "config", {"enabled": "true"})
Exemplo n.º 18
0
class AclLoader(object):

    ACL_TABLE = "ACL_TABLE"
    ACL_RULE = "ACL_RULE"
    ACL_TABLE_TYPE_MIRROR = "MIRROR"
    ACL_TABLE_TYPE_CTRLPLANE = "CTRLPLANE"
    CFG_MIRROR_SESSION_TABLE = "MIRROR_SESSION"
    STATE_MIRROR_SESSION_TABLE = "MIRROR_SESSION_TABLE"
    POLICER = "POLICER"
    SESSION_PREFIX = "everflow"
    SWITCH_CAPABILITY_TABLE = "SWITCH_CAPABILITY"
    ACL_ACTIONS_CAPABILITY_FIELD = "ACL_ACTIONS"
    ACL_ACTION_CAPABILITY_FIELD = "ACL_ACTION"

    min_priority = 1
    max_priority = 10000

    ethertype_map = {
        "ETHERTYPE_LLDP": 0x88CC,
        "ETHERTYPE_VLAN": 0x8100,
        "ETHERTYPE_ROCE": 0x8915,
        "ETHERTYPE_ARP": 0x0806,
        "ETHERTYPE_IPV4": 0x0800,
        "ETHERTYPE_IPV6": 0x86DD,
        "ETHERTYPE_MPLS": 0x8847
    }

    ip_protocol_map = {
        "IP_TCP": 6,
        "IP_ICMP": 1,
        "IP_UDP": 17,
        "IP_IGMP": 2,
        "IP_PIM": 103,
        "IP_RSVP": 46,
        "IP_GRE": 47,
        "IP_AUTH": 51,
        "IP_L2TP": 115
    }

    def __init__(self):
        self.yang_acl = None
        self.requested_session = None
        self.mirror_stage = None
        self.current_table = None
        self.tables_db_info = {}
        self.rules_db_info = {}
        self.rules_info = {}
        # Load global db config. This call is no-op in single npu platforms
        SonicDBConfig.load_sonic_global_db_config()
        self.sessions_db_info = {}
        self.configdb = ConfigDBConnector()
        self.configdb.connect()
        self.statedb = SonicV2Connector(host="127.0.0.1")
        self.statedb.connect(self.statedb.STATE_DB)

        # For multi-npu architecture we will have both global and per front asic namespace.
        # Global namespace will be used for Control plane ACL which are via IPTables.
        # Per ASIC namespace will be used for Data and Everflow ACL's.
        # Global Configdb will have all ACL information for both Ctrl and Data/Evereflow ACL's
        # and will be used as souurce of truth for ACL modification to config DB which will be done to both Global DB and
        # front asic namespace

        self.per_npu_configdb = {}

        # State DB are used for to get mirror Session monitor port.
        # For multi-npu platforms each asic namespace can have different monitor port
        # dependinding on which route to session destination ip. So for multi-npu
        # platforms we get state db for all front asic namespace in addition to

        self.per_npu_statedb = {}

        # Getting all front asic namespace and correspding config and state DB connector

        namespaces = device_info.get_all_namespaces()
        for front_asic_namespaces in namespaces['front_ns']:
            self.per_npu_configdb[front_asic_namespaces] = ConfigDBConnector(
                use_unix_socket_path=True, namespace=front_asic_namespaces)
            self.per_npu_configdb[front_asic_namespaces].connect()
            self.per_npu_statedb[front_asic_namespaces] = SonicV2Connector(
                use_unix_socket_path=True, namespace=front_asic_namespaces)
            self.per_npu_statedb[front_asic_namespaces].connect(
                self.per_npu_statedb[front_asic_namespaces].STATE_DB)

        self.read_tables_info()
        self.read_rules_info()
        self.read_sessions_info()
        self.read_policers_info()

    def read_tables_info(self):
        """
        Read ACL_TABLE table from configuration database
        :return:
        """
        self.tables_db_info = self.configdb.get_table(self.ACL_TABLE)

    def get_tables_db_info(self):
        return self.tables_db_info

    def read_rules_info(self):
        """
        Read ACL_RULE table from configuration database
        :return:
        """
        self.rules_db_info = self.configdb.get_table(self.ACL_RULE)

    def get_rules_db_info(self):
        return self.rules_db_info

    def read_policers_info(self):
        """
        Read POLICER table from configuration database
        :return:
        """

        # For multi-npu platforms we will read from any one of front asic namespace
        # config db as the information should be same across all config db
        if self.per_npu_configdb:
            namespace_configdb = list(self.per_npu_configdb.values())[0]
            self.policers_db_info = namespace_configdb.get_table(self.POLICER)
        else:
            self.policers_db_info = self.configdb.get_table(self.POLICER)

    def get_policers_db_info(self):
        return self.policers_db_info

    def read_sessions_info(self):
        """
        Read MIRROR_SESSION table from configuration database
        :return:
        """

        # For multi-npu platforms we will read from any one of front asic namespace
        # config db as the information should be same across all config db
        if self.per_npu_configdb:
            namespace_configdb = list(self.per_npu_configdb.values())[0]
            self.sessions_db_info = namespace_configdb.get_table(
                self.CFG_MIRROR_SESSION_TABLE)
        else:
            self.sessions_db_info = self.configdb.get_table(
                self.CFG_MIRROR_SESSION_TABLE)
        for key in self.sessions_db_info:
            if self.per_npu_statedb:
                # For multi-npu platforms we will read from all front asic name space
                # statedb as the monitor port will be differnt for each asic
                # and it's status also might be different (ideally should not happen)
                # We will store them as dict of 'asic' : value
                self.sessions_db_info[key]["status"] = {}
                self.sessions_db_info[key]["monitor_port"] = {}
                for namespace_key, namespace_statedb in self.per_npu_statedb.items(
                ):
                    state_db_info = namespace_statedb.get_all(
                        self.statedb.STATE_DB,
                        "{}|{}".format(self.STATE_MIRROR_SESSION_TABLE, key))
                    self.sessions_db_info[key]["status"][
                        namespace_key] = state_db_info.get(
                            "status", "inactive") if state_db_info else "error"
                    self.sessions_db_info[key][
                        "monitor_port"][namespace_key] = state_db_info.get(
                            "monitor_port", "") if state_db_info else ""
            else:
                state_db_info = self.statedb.get_all(
                    self.statedb.STATE_DB,
                    "{}|{}".format(self.STATE_MIRROR_SESSION_TABLE, key))
                self.sessions_db_info[key]["status"] = state_db_info.get(
                    "status", "inactive") if state_db_info else "error"
                self.sessions_db_info[key]["monitor_port"] = state_db_info.get(
                    "monitor_port", "") if state_db_info else ""

    def get_sessions_db_info(self):
        return self.sessions_db_info

    def get_session_name(self):
        """
        Get requested mirror session name or default session
        :return: Mirror session name
        """
        if self.requested_session:
            return self.requested_session

        for key in self.get_sessions_db_info():
            if key.startswith(self.SESSION_PREFIX):
                return key

        return None

    def set_table_name(self, table_name):
        """
        Set table name to restrict the table to be modified
        :param table_name: Table name
        :return:
        """
        if not self.is_table_valid(table_name):
            warning("Table \"%s\" not found" % table_name)

        self.current_table = table_name

    def set_session_name(self, session_name):
        """
        Set session name to be used in ACL rule action
        :param session_name: Mirror session name
        :return:
        """
        if session_name not in self.get_sessions_db_info():
            raise AclLoaderException("Session %s does not exist" %
                                     session_name)

        self.requested_session = session_name

    def set_mirror_stage(self, stage):
        """
        Set mirror stage to be used in ACL mirror rule action
        :param session_name: stage 'ingress'/'egress'
        :return:
        """
        self.mirror_stage = stage.upper()

    def set_max_priority(self, priority):
        """
        Set rules max priority
        :param priority: Rules max priority
        :return:
        """
        self.max_priority = int(priority)

    def is_table_valid(self, tname):
        return self.tables_db_info.get(tname)

    def is_table_mirror(self, tname):
        """
        Check if ACL table type is ACL_TABLE_TYPE_MIRROR or ACL_TABLE_TYPE_MIRRORV6
        :param tname: ACL table name
        :return: True if table type is MIRROR or MIRRORV6 else False
        """
        return self.tables_db_info[tname]['type'].upper().startswith(
            self.ACL_TABLE_TYPE_MIRROR)

    def is_table_control_plane(self, tname):
        """
        Check if ACL table type is ACL_TABLE_TYPE_CTRLPLANE
        :param tname: ACL table name
        :return: True if table type is ACL_TABLE_TYPE_CTRLPLANE else False
        """
        return self.tables_db_info[tname]['type'].upper(
        ) == self.ACL_TABLE_TYPE_CTRLPLANE

    @staticmethod
    def parse_acl_json(filename):
        yang_acl = pybindJSON.load(filename, openconfig_acl, "openconfig_acl")
        # Check pybindJSON parsing
        # pybindJSON.load will silently return an empty json object if input invalid
        with open(filename, 'r') as f:
            plain_json = json.load(f)
            if len(plain_json['acl']['acl-sets']['acl-set']) != len(
                    yang_acl.acl.acl_sets.acl_set):
                raise AclLoaderException("Invalid input file %s" % filename)
        return yang_acl

    def load_rules_from_file(self, filename):
        """
        Load file with ACL rules configuration in openconfig ACL format. Convert rules
        to Config DB schema.
        :param filename: File in openconfig ACL format
        :return:
        """
        self.yang_acl = AclLoader.parse_acl_json(filename)
        self.convert_rules()

    def convert_action(self, table_name, rule_idx, rule):
        rule_props = {}

        if rule.actions.config.forwarding_action == "ACCEPT":
            if self.is_table_control_plane(table_name):
                rule_props[AclAction.PACKET] = PacketAction.ACCEPT
            elif self.is_table_mirror(table_name):
                session_name = self.get_session_name()
                if not session_name:
                    raise AclLoaderException(
                        "Mirroring session does not exist")

                if self.mirror_stage == Stage.INGRESS:
                    mirror_action = AclAction.MIRROR_INGRESS
                elif self.mirror_stage == Stage.EGRESS:
                    mirror_action = AclAction.MIRROR_EGRESS
                else:
                    raise AclLoaderException(
                        "Invalid mirror stage passed {}".format(
                            self.mirror_stage))

                rule_props[mirror_action] = session_name
            else:
                rule_props[AclAction.PACKET] = PacketAction.FORWARD
        elif rule.actions.config.forwarding_action == "DROP":
            rule_props[AclAction.PACKET] = PacketAction.DROP
        elif rule.actions.config.forwarding_action == "REJECT":
            rule_props[AclAction.PACKET] = PacketAction.DROP
        else:
            raise AclLoaderException(
                "Unknown rule action {} in table {}, rule {}".format(
                    rule.actions.config.forwarding_action, table_name,
                    rule_idx))

        if not self.validate_actions(table_name, rule_props):
            raise AclLoaderException(
                "Rule action {} is not supported in table {}, rule {}".format(
                    rule.actions.config.forwarding_action, table_name,
                    rule_idx))

        return rule_props

    def validate_actions(self, table_name, action_props):
        if self.is_table_control_plane(table_name):
            return True

        action_count = len(action_props)

        if table_name not in self.tables_db_info:
            raise AclLoaderException(
                "Table {} does not exist".format(table_name))

        stage = self.tables_db_info[table_name].get("stage", Stage.INGRESS)

        # check if per npu state db is there then read using first state db
        # else read from global statedb
        if self.per_npu_statedb:
            # For multi-npu we will read using anyone statedb connector for front asic namespace.
            # Same information should be there in all state DB's
            # as it is static information about switch capability
            namespace_statedb = list(self.per_npu_statedb.values())[0]
            capability = namespace_statedb.get_all(
                self.statedb.STATE_DB,
                "{}|switch".format(self.SWITCH_CAPABILITY_TABLE))
        else:
            capability = self.statedb.get_all(
                self.statedb.STATE_DB,
                "{}|switch".format(self.SWITCH_CAPABILITY_TABLE))
        for action_key in dict(action_props):
            key = "{}|{}".format(self.ACL_ACTIONS_CAPABILITY_FIELD,
                                 stage.upper())
            if key not in capability:
                del action_props[action_key]
                continue

            values = capability[key].split(",")
            if action_key.upper() not in values:
                del action_props[action_key]
                continue

            if action_key == AclAction.PACKET:
                # Check if action_value is supported
                action_value = action_props[action_key]
                key = "{}|{}".format(self.ACL_ACTION_CAPABILITY_FIELD,
                                     action_key.upper())
                if key not in capability:
                    del action_props[action_key]
                    continue

                if action_value not in capability[key]:
                    del action_props[action_key]
                    continue

        return action_count == len(action_props)

    def convert_l2(self, table_name, rule_idx, rule):
        rule_props = {}

        if rule.l2.config.ethertype:
            if rule.l2.config.ethertype in self.ethertype_map:
                rule_props["ETHER_TYPE"] = self.ethertype_map[
                    rule.l2.config.ethertype]
            else:
                try:
                    rule_props["ETHER_TYPE"] = int(rule.l2.config.ethertype)
                except:
                    raise AclLoaderException(
                        "Failed to convert ethertype %s table %s rule %s" %
                        (rule.l2.config.ethertype, table_name, rule_idx))

        return rule_props

    def convert_ip(self, table_name, rule_idx, rule):
        rule_props = {}

        # FIXME: 0 is a valid protocol number, but openconfig seems to use it as a default value,
        # so there isn't currently a good way to check if the user defined proto=0 or not.
        if rule.ip.config.protocol:
            if rule.ip.config.protocol in self.ip_protocol_map:
                rule_props["IP_PROTOCOL"] = self.ip_protocol_map[
                    rule.ip.config.protocol]
            else:
                try:
                    int(rule.ip.config.protocol)
                except:
                    raise AclLoaderException(
                        "Unknown rule protocol %s in table %s, rule %d!" %
                        (rule.ip.config.protocol, table_name, rule_idx))

                rule_props["IP_PROTOCOL"] = rule.ip.config.protocol

        if rule.ip.config.source_ip_address:
            source_ip_address = rule.ip.config.source_ip_address.encode(
                "ascii")
            if ipaddress.ip_network(source_ip_address).version == 4:
                rule_props["SRC_IP"] = source_ip_address
            else:
                rule_props["SRC_IPV6"] = source_ip_address

        if rule.ip.config.destination_ip_address:
            destination_ip_address = rule.ip.config.destination_ip_address.encode(
                "ascii")
            if ipaddress.ip_network(destination_ip_address).version == 4:
                rule_props["DST_IP"] = destination_ip_address
            else:
                rule_props["DST_IPV6"] = destination_ip_address

        # NOTE: DSCP is available only for MIRROR table
        if self.is_table_mirror(table_name):
            if rule.ip.config.dscp:
                rule_props["DSCP"] = rule.ip.config.dscp

        return rule_props

    def convert_port(self, port):
        """
        Convert port field format from openconfig ACL to Config DB schema
        :param port: String, ACL port number or range in openconfig format
        :return: Tuple, first value is converted port string,
            second value is boolean, True if value is a port range, False
            if it is a single port value
        """
        # OpenConfig port range is of the format "####..####", whereas
        # Config DB format is "####-####"
        if ".." in port:
            return port.replace("..", "-"), True
        else:
            return port, False

    def convert_transport(self, table_name, rule_idx, rule):
        rule_props = {}

        if rule.transport.config.source_port:
            port, is_range = self.convert_port(
                str(rule.transport.config.source_port))
            rule_props[
                "L4_SRC_PORT_RANGE" if is_range else "L4_SRC_PORT"] = port
        if rule.transport.config.destination_port:
            port, is_range = self.convert_port(
                str(rule.transport.config.destination_port))
            rule_props[
                "L4_DST_PORT_RANGE" if is_range else "L4_DST_PORT"] = port

        tcp_flags = 0x00

        for flag in rule.transport.config.tcp_flags:
            if flag == "TCP_FIN":
                tcp_flags |= 0x01
            if flag == "TCP_SYN":
                tcp_flags |= 0x02
            if flag == "TCP_RST":
                tcp_flags |= 0x04
            if flag == "TCP_PSH":
                tcp_flags |= 0x08
            if flag == "TCP_ACK":
                tcp_flags |= 0x10
            if flag == "TCP_URG":
                tcp_flags |= 0x20
            if flag == "TCP_ECE":
                tcp_flags |= 0x40
            if flag == "TCP_CWR":
                tcp_flags |= 0x80

        if tcp_flags:
            rule_props["TCP_FLAGS"] = '0x{:02x}/0x{:02x}'.format(
                tcp_flags, tcp_flags)

        return rule_props

    def convert_input_interface(self, table_name, rule_idx, rule):
        rule_props = {}

        if rule.input_interface.interface_ref.config.interface:
            rule_props[
                "IN_PORTS"] = rule.input_interface.interface_ref.config.interface

        return rule_props

    def convert_rule_to_db_schema(self, table_name, rule):
        """
        Convert rules format from openconfig ACL to Config DB schema
        :param table_name: ACL table name to which rule belong
        :param rule: ACL rule in openconfig format
        :return: dict with Config DB schema
        """
        rule_idx = int(rule.config.sequence_id)
        rule_props = {}
        rule_data = {(table_name, "RULE_" + str(rule_idx)): rule_props}

        rule_props["PRIORITY"] = str(self.max_priority - rule_idx)

        deep_update(rule_props, self.convert_action(table_name, rule_idx,
                                                    rule))
        deep_update(rule_props, self.convert_l2(table_name, rule_idx, rule))
        deep_update(rule_props, self.convert_ip(table_name, rule_idx, rule))
        deep_update(rule_props,
                    self.convert_transport(table_name, rule_idx, rule))
        deep_update(rule_props,
                    self.convert_input_interface(table_name, rule_idx, rule))

        return rule_data

    def deny_rule(self, table_name):
        """
        Create default deny rule in Config DB format
        :param table_name: ACL table name to which rule belong
        :return: dict with Config DB schema
        """
        rule_props = {}
        rule_data = {(table_name, "DEFAULT_RULE"): rule_props}
        rule_props["PRIORITY"] = str(self.min_priority)
        rule_props["PACKET_ACTION"] = "DROP"
        if 'v6' in table_name.lower():
            rule_props["ETHER_TYPE"] = str(
                self.ethertype_map["ETHERTYPE_IPV6"])
        else:
            rule_props["ETHER_TYPE"] = str(
                self.ethertype_map["ETHERTYPE_IPV4"])
        return rule_data

    def convert_rules(self):
        """
        Convert rules in openconfig ACL format to Config DB schema
        :return:
        """
        for acl_set_name in self.yang_acl.acl.acl_sets.acl_set:
            table_name = acl_set_name.replace(" ", "_").replace(
                "-", "_").upper().encode('ascii')
            acl_set = self.yang_acl.acl.acl_sets.acl_set[acl_set_name]

            if not self.is_table_valid(table_name):
                warning("%s table does not exist" % (table_name))
                continue

            if self.current_table is not None and self.current_table != table_name:
                continue

            for acl_entry_name in acl_set.acl_entries.acl_entry:
                acl_entry = acl_set.acl_entries.acl_entry[acl_entry_name]
                try:
                    rule = self.convert_rule_to_db_schema(
                        table_name, acl_entry)
                    deep_update(self.rules_info, rule)
                except AclLoaderException as ex:
                    error("Error processing rule %s: %s. Skipped." %
                          (acl_entry_name, ex))

            if not self.is_table_mirror(table_name):
                deep_update(self.rules_info, self.deny_rule(table_name))

    def full_update(self):
        """
        Perform full update of ACL rules configuration. All existing rules
        will be removed. New rules loaded from file will be installed. If
        the current_table is not empty, only rules within that table will
        be removed and new rules in that table will be installed.
        :return:
        """
        for key in self.rules_db_info:
            if self.current_table is None or self.current_table == key[0]:
                self.configdb.mod_entry(self.ACL_RULE, key, None)
                # Program for per front asic namespace also if present
                for namespace_configdb in self.per_npu_configdb.values():
                    namespace_configdb.mod_entry(self.ACL_RULE, key, None)

        self.configdb.mod_config({self.ACL_RULE: self.rules_info})
        # Program for per front asic namespace also if present
        for namespace_configdb in self.per_npu_configdb.values():
            namespace_configdb.mod_config({self.ACL_RULE: self.rules_info})

    def incremental_update(self):
        """
        Perform incremental ACL rules configuration update. Get existing rules from
        Config DB. Compare with rules specified in file and perform corresponding
        modifications.
        :return:
        """

        # TODO: Until we test ASIC behavior, we cannot assume that we can insert
        # dataplane ACLs and shift existing ACLs. Therefore, we perform a full
        # update on dataplane ACLs, and only perform an incremental update on
        # control plane ACLs.

        new_rules = set(self.rules_info.keys())
        new_dataplane_rules = set()
        new_controlplane_rules = set()
        current_rules = set(self.rules_db_info.keys())
        current_dataplane_rules = set()
        current_controlplane_rules = set()

        for key in new_rules:
            table_name = key[0]
            if self.tables_db_info[table_name]['type'].upper(
            ) == self.ACL_TABLE_TYPE_CTRLPLANE:
                new_controlplane_rules.add(key)
            else:
                new_dataplane_rules.add(key)

        for key in current_rules:
            table_name = key[0]
            if self.tables_db_info[table_name]['type'].upper(
            ) == self.ACL_TABLE_TYPE_CTRLPLANE:
                current_controlplane_rules.add(key)
            else:
                current_dataplane_rules.add(key)

        # Remove all existing dataplane rules
        for key in current_dataplane_rules:
            self.configdb.mod_entry(self.ACL_RULE, key, None)
            # Program for per-asic namespace also if present
            for namespace_configdb in self.per_npu_configdb.values():
                namespace_configdb.mod_entry(self.ACL_RULE, key, None)

        # Add all new dataplane rules
        for key in new_dataplane_rules:
            self.configdb.mod_entry(self.ACL_RULE, key, self.rules_info[key])
            # Program for per-asic namespace corresponding to front asic also if present.
            for namespace_configdb in self.per_npu_configdb.values():
                namespace_configdb.mod_entry(self.ACL_RULE, key,
                                             self.rules_info[key])

        added_controlplane_rules = new_controlplane_rules.difference(
            current_controlplane_rules)
        removed_controlplane_rules = current_controlplane_rules.difference(
            new_controlplane_rules)
        existing_controlplane_rules = new_rules.intersection(
            current_controlplane_rules)

        for key in added_controlplane_rules:
            self.configdb.mod_entry(self.ACL_RULE, key, self.rules_info[key])
            # Program for per-asic namespace corresponding to front asic also if present.
            # For control plane ACL it's not needed but to keep all db in sync program everywhere
            for namespace_configdb in self.per_npu_configdb.values():
                namespace_configdb.mod_entry(self.ACL_RULE, key,
                                             self.rules_info[key])

        for key in removed_controlplane_rules:
            self.configdb.mod_entry(self.ACL_RULE, key, None)
            # Program for per-asic namespace corresponding to front asic also if present.
            # For control plane ACL it's not needed but to keep all db in sync program everywhere
            for namespace_configdb in self.per_npu_configdb.values():
                namespace_configdb.mod_entry(self.ACL_RULE, key, None)

        for key in existing_controlplane_rules:
            if cmp(self.rules_info[key], self.rules_db_info[key]) != 0:
                self.configdb.set_entry(self.ACL_RULE, key,
                                        self.rules_info[key])
                # Program for per-asic namespace corresponding to front asic also if present.
                # For control plane ACL it's not needed but to keep all db in sync program everywhere
                for namespace_configdb in self.per_npu_configdb.values():
                    namespace_configdb.set_entry(self.ACL_RULE, key,
                                                 self.rules_info[key])

    def delete(self, table=None, rule=None):
        """
        :param table:
        :param rule:
        :return:
        """
        for key in self.rules_db_info:
            if not table or table == key[0]:
                if not rule or rule == key[1]:
                    self.configdb.set_entry(self.ACL_RULE, key, None)
                    # Program for per-asic namespace corresponding to front asic also if present.
                    for namespace_configdb in self.per_npu_configdb.values():
                        namespace_configdb.set_entry(self.ACL_RULE, key, None)

    def show_table(self, table_name):
        """
        Show ACL table configuration.
        :param table_name: Optional. ACL table name. Filter tables by specified name.
        :return:
        """
        header = ("Name", "Type", "Binding", "Description", "Stage")

        data = []
        for key, val in self.get_tables_db_info().items():
            if table_name and key != table_name:
                continue

            stage = val.get("stage", Stage.INGRESS).lower()

            if val["type"] == AclLoader.ACL_TABLE_TYPE_CTRLPLANE:
                services = natsorted(val["services"])
                data.append(
                    [key, val["type"], services[0], val["policy_desc"], stage])

                if len(services) > 1:
                    for service in services[1:]:
                        data.append(["", "", service, "", ""])
            else:
                if not val["ports"]:
                    data.append(
                        [key, val["type"], "", val["policy_desc"], stage])
                else:
                    ports = natsorted(val["ports"])
                    data.append([
                        key, val["type"], ports[0], val["policy_desc"], stage
                    ])

                    if len(ports) > 1:
                        for port in ports[1:]:
                            data.append(["", "", port, "", ""])

        print(
            tabulate.tabulate(data,
                              headers=header,
                              tablefmt="simple",
                              missingval=""))

    def show_session(self, session_name):
        """
        Show mirror session configuration.
        :param session_name: Optional. Mirror session name. Filter sessions by specified name.
        :return:
        """
        erspan_header = ("Name", "Status", "SRC IP", "DST IP", "GRE", "DSCP",
                         "TTL", "Queue", "Policer", "Monitor Port", "SRC Port",
                         "Direction")
        span_header = ("Name", "Status", "DST Port", "SRC Port", "Direction",
                       "Queue", "Policer")

        erspan_data = []
        span_data = []
        for key, val in self.get_sessions_db_info().items():
            if session_name and key != session_name:
                continue

            if val.get("type") == "SPAN":
                span_data.append([
                    key,
                    val.get("status", ""),
                    val.get("dst_port", ""),
                    val.get("src_port", ""),
                    val.get("direction", "").lower(),
                    val.get("queue", ""),
                    val.get("policer", "")
                ])
            else:
                erspan_data.append([
                    key,
                    val.get("status", ""),
                    val.get("src_ip", ""),
                    val.get("dst_ip", ""),
                    val.get("gre_type", ""),
                    val.get("dscp", ""),
                    val.get("ttl", ""),
                    val.get("queue", ""),
                    val.get("policer", ""),
                    val.get("monitor_port", ""),
                    val.get("src_port", ""),
                    val.get("direction", "").lower()
                ])

        print("ERSPAN Sessions")
        print(
            tabulate.tabulate(erspan_data,
                              headers=erspan_header,
                              tablefmt="simple",
                              missingval=""))
        print("\nSPAN Sessions")
        print(
            tabulate.tabulate(span_data,
                              headers=span_header,
                              tablefmt="simple",
                              missingval=""))

    def show_policer(self, policer_name):
        """
        Show policer configuration.
        :param policer_name: Optional. Policer name. Filter policers by specified name.
        :return:
        """
        header = ("Name", "Type", "Mode", "CIR", "CBS")

        data = []
        for key, val in self.get_policers_db_info().items():
            if policer_name and key != policer_name:
                continue

            data.append([
                key, val["meter_type"], val["mode"],
                val.get("cir", ""),
                val.get("cbs", "")
            ])

        print(
            tabulate.tabulate(data,
                              headers=header,
                              tablefmt="simple",
                              missingval=""))

    def show_rule(self, table_name, rule_id):
        """
        Show ACL rules configuration.
        :param table_name: Optional. ACL table name. Filter rules by specified table name.
        :param rule_id: Optional. ACL rule name. Filter rule by specified rule name.
        :return:
        """
        header = ("Table", "Rule", "Priority", "Action", "Match")

        def pop_priority(val):
            priority = "N/A"
            for key in dict(val):
                if (key.upper() == "PRIORITY"):
                    priority = val.pop(key)
                    return priority
            return priority

        def pop_action(val):
            action = ""

            for key in dict(val):
                key = key.upper()
                if key == AclAction.PACKET:
                    action = val.pop(key)
                elif key == AclAction.REDIRECT:
                    action = "REDIRECT: {}".format(val.pop(key))
                elif key in (AclAction.MIRROR, AclAction.MIRROR_INGRESS):
                    action = "MIRROR INGRESS: {}".format(val.pop(key))
                elif key == AclAction.MIRROR_EGRESS:
                    action = "MIRROR EGRESS: {}".format(val.pop(key))
                else:
                    continue

            return action

        def pop_matches(val):
            matches = list(sorted(["%s: %s" % (k, val[k]) for k in val]))
            if len(matches) == 0:
                matches.append("N/A")
            return matches

        raw_data = []
        for (tname, rid), val in self.get_rules_db_info().items():

            if table_name and table_name != tname:
                continue

            if rule_id and rule_id != rid:
                continue

            priority = pop_priority(val)
            action = pop_action(val)
            matches = pop_matches(val)

            rule_data = [[tname, rid, priority, action, matches[0]]]
            if len(matches) > 1:
                for m in matches[1:]:
                    rule_data.append(["", "", "", "", m])

            raw_data.append([priority, rule_data])

        def cmp_rules(a, b):
            return cmp(a[0], b[0])

        raw_data.sort(cmp_rules)
        raw_data.reverse()

        data = []
        for _, d in raw_data:
            data += d

        print(
            tabulate.tabulate(data,
                              headers=header,
                              tablefmt="simple",
                              missingval=""))
Exemplo n.º 19
0
def num_dumps(kdump_num_dumps):
    """Set max number of dump files for kdump"""
    config_db = ConfigDBConnector()
    if config_db is not None:
        config_db.connect()
        config_db.mod_entry("KDUMP", "config", {"num_dumps": kdump_num_dumps})
Exemplo n.º 20
0
class Tam(object):
    def __init__(self):
        # connect CONFIG DB
        self.config_db = ConfigDBConnector()
        self.config_db.connect()

        # connect APPL DB
        self.app_db = ConfigDBConnector()
        self.app_db.db_connect('APPL_DB')

    def get_tam_collector_info(self, k):
        api_response = {}
        key = TAM_COLLECTOR_TABLE_PREFIX + '|' + k
        raw_coll_data = self.config_db.get_all(self.config_db.CONFIG_DB, key)
        api_response['coll-key'] = k
        api_response['each-coll-data'] = raw_coll_data
        return api_response, raw_coll_data

    def get_print_all_tam_collectors(self, name):
        coll_dict = {}
        coll_list = []
        if name != 'all':
            api_response, entryfound = self.get_tam_collector_info(name)
            if entryfound is not None:
                coll_list.append(api_response)
        else:
            table_data = self.config_db.get_keys(TAM_COLLECTOR_TABLE_PREFIX)
            # Get data for all keys
            for k in table_data:
                api_each_flow_response, entryfound = self.get_tam_collector_info(
                    k)
                if entryfound is not None:
                    coll_list.append(api_each_flow_response)

        coll_dict['flow-list'] = coll_list
        show_cli_output("show_collector.j2", coll_dict)
        return

    def config_device_id(self, args):
        key = 'device'
        entry = self.config_db.get_entry(TAM_DEVICE_TABLE_PREFIX, key)
        if entry is None:
            if args.deviceid:
                self.config_db.set_entry(TAM_DEVICE_TABLE_PREFIX, key,
                                         {'deviceid': args.deviceid})
        else:
            if args.deviceid:
                entry_value = entry.get('deviceid', [])

                if entry_value != args.deviceid:
                    self.config_db.mod_entry(TAM_DEVICE_TABLE_PREFIX, key,
                                             {'deviceid': args.deviceid})
        return

    def config_collector(self, args):
        if args.iptype == 'ipv4':
            if args.ipaddr == "0.0.0.0":
                print "Collector IP should be non-zero ip address"
                return False

        if args.iptype == 'ipv6':
            print "IPv6 Collector type not supported"
            return False

        self.config_db.mod_entry(
            TAM_COLLECTOR_TABLE_PREFIX, args.collectorname, {
                'ipaddress-type': args.iptype,
                'ipaddress': args.ipaddr,
                'port': args.port
            })

        return

    def clear_device_id(self):
        key = 'device'
        entry = self.config_db.get_entry(TAM_DEVICE_TABLE_PREFIX, key)
        if entry:
            self.config_db.set_entry(TAM_DEVICE_TABLE_PREFIX, key, None)
        return

    def clear_collector(self, args):
        key = args.collectorname
        entry = self.config_db.get_entry(TAM_COLLECTOR_TABLE_PREFIX, key)
        if entry:
            self.config_db.set_entry(TAM_COLLECTOR_TABLE_PREFIX, key, None)
        else:
            print "Entry Not Found"
            return False
        return

    def show_device_id(self):
        key = TAM_DEVICE_TABLE_PREFIX + '|' + 'device'
        data = self.config_db.get_all(self.config_db.CONFIG_DB, key)
        print "TAM Device identifier"
        print "-------------------------------"
        if data:
            if 'deviceid' in data:
                print "Device Identifier    - ", data['deviceid']
        return

    def show_collector(self, args):
        self.get_print_all_tam_collectors(args.collectorname)
        return