OpenStack-Neutron-Fwaas-代码【二】

  上一节从代码层面来讲解了fwaas的流程,这里通过具体查看iptables规则来说下应用规则的流程:

1.首先通过命令获取当前路由中的规则

#ip netns exec qrouter-[router-uuid] iptables-save -c >> rules

2.查看文件,这里我给定一个实例文件,这里因为我们只关心filter表,其他表去除

# Generated by iptables-save v1.4.21 on Fri May 22 15:59:01 2015
*filter
:INPUT ACCEPT [6425:953808]
:FORWARD ACCEPT [5:408]
:OUTPUT ACCEPT [9:972]  #这里往上是三个内置链

:neutron-filter-top - [0:0] #这是唯一一个非包装链

:neutron-l3-agent-FORWARD - [0:0]
:neutron-l3-agent-INPUT - [0:0]
:neutron-l3-agent-OUTPUT - [0:0]
:neutron-l3-agent-fwaas-defau - [0:0]
:neutron-l3-agent-iv4f7e1ffb5 - [0:0]
:neutron-l3-agent-local - [0:0]
:neutron-l3-agent-ov4f7e1ffb5 - [0:0]
:neutron-openvswi-FORWARD - [0:0]
:neutron-openvswi-INPUT - [0:0]
:neutron-openvswi-OUTPUT - [0:0]
:neutron-openvswi-ia45dd659-2 - [0:0]
:neutron-openvswi-local - [0:0]
:neutron-openvswi-oa45dd659-2 - [0:0]
:neutron-openvswi-sg-chain - [0:0]
:neutron-openvswi-sg-fallback - [0:0]
:neutron-vpn-agen-FORWARD - [0:0]
:neutron-vpn-agen-INPUT - [0:0]
:neutron-vpn-agen-OUTPUT - [0:0]
:neutron-vpn-agen-fwaas-defau - [0:0]
:neutron-vpn-agen-iv4f7e1ffb5 - [0:0]
:neutron-vpn-agen-local - [0:0]
:neutron-vpn-agen-ov4f7e1ffb5 - [0:0]  #这里是包装链,包装名称通过os.path.basename(inspect.stack()[-1][1])[:16]获取
[15606:1868567] -A INPUT -j neutron-vpn-agen-INPUT
[15621:1870099] -A INPUT -j neutron-l3-agent-INPUT
[10406:1260231] -A INPUT -j neutron-openvswi-INPUT #往上三个将input包装链作为跳转规则添加到内置input链中
[5:408] -A FORWARD -j neutron-filter-top
[5:408] -A FORWARD -j neutron-vpn-agen-FORWARD
[5:408] -A FORWARD -j neutron-l3-agent-FORWARD
[0:0] -A FORWARD -j neutron-openvswi-FORWARD #往上三个将forward包装链作为跳转规则添加到内置forward链中
[9:972] -A OUTPUT -j neutron-filter-top
[9:972] -A OUTPUT -j neutron-vpn-agen-OUTPUT
[9:972] -A OUTPUT -j neutron-l3-agent-OUTPUT
[0:0] -A OUTPUT -j neutron-openvswi-OUTPUT #往上三个将output包装链作为跳转规则添加到内置output链中
[14:1380] -A neutron-filter-top -j neutron-vpn-agen-local
[14:1380] -A neutron-filter-top -j neutron-l3-agent-local
[0:0] -A neutron-filter-top -j neutron-openvswi-local
[0:0] -A neutron-l3-agent-FORWARD -o qr-+ -j neutron-l3-agent-iv4f7e1ffb5
[0:0] -A neutron-l3-agent-FORWARD -i qr-+ -j neutron-l3-agent-ov4f7e1ffb5 #将neutron-l3-agent-ov4f7e1ffb5链作为跳转规则添加到neutron-l3-agent-FORWARD
[0:0] -A neutron-l3-agent-FORWARD -o qr-+ -j neutron-l3-agent-fwaas-defau
[0:0] -A neutron-l3-agent-FORWARD -i qr-+ -j neutron-l3-agent-fwaas-defau  #将neutron-l3-agent-fwaas-defau链作为跳转规则添加到neutron-l3-agent-FORWARD
[0:0] -A neutron-l3-agent-INPUT -d 127.0.0.1/32 -p tcp -m tcp --dport 9697 -j ACCEPT #默认规则

[0:0] -A neutron-l3-agent-fwaas-defau -j DROP #neutron-l3-agent-fwaas-defau链中只有一条drop规则
[0:0] -A neutron-l3-agent-iv4f7e1ffb5 -m state --state INVALID -j DROP
[0:0] -A neutron-l3-agent-iv4f7e1ffb5 -m state --state RELATED,ESTABLISHED -j ACCEPT #这两条规则是在初始化neutron-l3-agent-iv4f7e1ffb5链的时候添加的
[0:0] -A neutron-l3-agent-iv4f7e1ffb5 -s 10.10.10.0/24 -d 192.168.1.0/24 -p tcp -j DROP #界面添加的用户规则
[0:0] -A neutron-l3-agent-ov4f7e1ffb5 -m state --state INVALID -j DROP
[0:0] -A neutron-l3-agent-ov4f7e1ffb5 -m state --state RELATED,ESTABLISHED -j ACCEPT #这两条规则是在初始化neutron-l3-agent-ov4f7e1ffb5链的时候添加的
[0:0] -A neutron-l3-agent-ov4f7e1ffb5 -s 10.10.10.0/24 -d 192.168.1.0/24 -p tcp -j DROP #界面添加的用户规则 ,可以看到是同时将界面规则添加到出入链中
[0:0] -A neutron-openvswi-FORWARD -i qg-a45dd659-23 -j neutron-openvswi-sg-chain
[0:0] -A neutron-openvswi-FORWARD -o qg-a45dd659-23 -j neutron-openvswi-sg-chain
[10406:1260231] -A neutron-openvswi-INPUT -j neutron-openvswi-oa45dd659-2
[0:0] -A neutron-openvswi-ia45dd659-2 -m state --state INVALID -j DROP
[0:0] -A neutron-openvswi-ia45dd659-2 -m state --state RELATED,ESTABLISHED -j RETURN
[0:0] -A neutron-openvswi-ia45dd659-2 -s 192.168.1.12/32 -p udp -m udp --sport 67 --dport 68 -j RETURN
[0:0] -A neutron-openvswi-ia45dd659-2 -j neutron-openvswi-sg-fallback
[983:322818] -A neutron-openvswi-oa45dd659-2 -p udp -m udp --sport 68 --dport 67 -j RETURN
[0:0] -A neutron-openvswi-oa45dd659-2 -p tcp -m tcp --dport 22 -j RETURN
[125:41000] -A neutron-openvswi-oa45dd659-2 -p udp -m udp --sport 67 --dport 68 -j DROP
[0:0] -A neutron-openvswi-oa45dd659-2 -m state --state INVALID -j DROP
[0:0] -A neutron-openvswi-oa45dd659-2 -m state --state RELATED,ESTABLISHED -j RETURN
[9298:896413] -A neutron-openvswi-oa45dd659-2 -j neutron-openvswi-sg-fallback
[0:0] -A neutron-openvswi-sg-chain -i qg-a45dd659-23 -j neutron-openvswi-ia45dd659-2
[0:0] -A neutron-openvswi-sg-chain -o qg-a45dd659-23 -j neutron-openvswi-oa45dd659-2
[0:0] -A neutron-openvswi-sg-chain -j ACCEPT
[9298:896413] -A neutron-openvswi-sg-fallback -j DROP
[0:0] -A neutron-vpn-agen-FORWARD -o qr-+ -j neutron-vpn-agen-iv4f7e1ffb5
[0:0] -A neutron-vpn-agen-FORWARD -i qr-+ -j neutron-vpn-agen-ov4f7e1ffb5
[0:0] -A neutron-vpn-agen-FORWARD -o qr-+ -j neutron-vpn-agen-fwaas-defau
[0:0] -A neutron-vpn-agen-FORWARD -i qr-+ -j neutron-vpn-agen-fwaas-defau
[0:0] -A neutron-vpn-agen-INPUT -d 127.0.0.1/32 -p tcp -m tcp --dport 9697 -j ACCEPT
[0:0] -A neutron-vpn-agen-fwaas-defau -j DROP
[0:0] -A neutron-vpn-agen-iv4f7e1ffb5 -m state --state INVALID -j DROP
[0:0] -A neutron-vpn-agen-iv4f7e1ffb5 -m state --state RELATED,ESTABLISHED -j ACCEPT
[0:0] -A neutron-vpn-agen-iv4f7e1ffb5 -s 10.10.10.0/24 -d 192.168.1.0/24 -p tcp -j DROP
[0:0] -A neutron-vpn-agen-ov4f7e1ffb5 -m state --state INVALID -j DROP
[0:0] -A neutron-vpn-agen-ov4f7e1ffb5 -m state --state RELATED,ESTABLISHED -j ACCEPT
[0:0] -A neutron-vpn-agen-ov4f7e1ffb5 -s 10.10.10.0/24 -d 192.168.1.0/24 -p tcp -j DROP
COMMIT
# Completed on Fri May 22 16:48:38 2015

  

3. 代码中应用规则是这样的流程

代码路径:neutron\agent\linux\iptables_manager.py

def _apply_synchronized(self):
        """Apply the current in-memory set of iptables rules.

        This will blow away any rules left over from previous runs of the
        same component of Nova, and replace them with our current set of
        rules. This happens atomically, thanks to iptables-restore.

        """
        s = [(‘iptables‘, self.ipv4)]
        if self.use_ipv6:
            s += [(‘ip6tables‘, self.ipv6)]

        for cmd, tables in s:
            args = [‘%s-save‘ % (cmd,), ‘-c‘]
            if self.namespace:
                args = [‘ip‘, ‘netns‘, ‘exec‘, self.namespace] + args
            all_tables = self.execute(args, root_helper=self.root_helper)  #将已有的规则保存到all_tables对象中
            all_lines = all_tables.split(‘\n‘)
            # Traverse tables in sorted order for predictable dump output
            for table_name in sorted(tables):
                table = tables[table_name]
                start, end = self._find_table(all_lines, table_name) #查表,实际看下保存的结果就可以很容易的看出他的数据结构了
                all_lines[start:end] = self._modify_rules(  # 【3.1】重点看下这个方法
                    all_lines[start:end], table, table_name)

            args = [‘%s-restore‘ % (cmd,), ‘-c‘]
            if self.namespace:
                args = [‘ip‘, ‘netns‘, ‘exec‘, self.namespace] + args
            try:
                self.execute(args, process_input=‘\n‘.join(all_lines),
                             root_helper=self.root_helper) #将更新好的规则重新应用
            except RuntimeError as r_error:
                with excutils.save_and_reraise_exception():
                    try:
                        line_no = int(re.search(
                            ‘iptables-restore: line ([0-9]+?) failed‘,
                            str(r_error)).group(1))
                        context = IPTABLES_ERROR_LINES_OF_CONTEXT
                        log_start = max(0, line_no - context)
                        log_end = line_no + context
                    except AttributeError:
                        # line error wasn‘t found, print all lines instead
                        log_start = 0
                        log_end = len(all_lines)
                    log_lines = (‘%7d. %s‘ % (idx, l)
                                 for idx, l in enumerate(
                                     all_lines[log_start:log_end],
                                     log_start + 1)
                                 )
                    LOG.error(_("IPTablesManager.apply failed to apply the "
                                "following set of iptables rules:\n%s"),
                              ‘\n‘.join(log_lines))
        LOG.debug(_("IPTablesManager.apply completed with success"))

【3.1】 过滤规则

def _modify_rules(self, current_lines, table, table_name):
        # Chains are stored as sets to avoid duplicates.
        # Sort the output chains here to make their order predictable.
        unwrapped_chains = sorted(table.unwrapped_chains) #排序非包装链,我们知道就只有一个
        chains = sorted(table.chains) #排序包装链
        remove_chains = table.remove_chains
        rules = table.rules
        remove_rules = table.remove_rules

        if not current_lines:
            fake_table = [‘# Generated by iptables_manager‘,
                          ‘*‘ + table_name, ‘COMMIT‘,
                          ‘# Completed by iptables_manager‘]
            current_lines = fake_table

        # Fill old_filter with any chains or rules we might have added,
        # they could have a [packet:byte] count we want to preserve.
        # Fill new_filter with any chains or rules without our name in them.
        old_filter, new_filter = [], []
        for line in current_lines:
            (old_filter if self.wrap_name in line else
             new_filter).append(line.strip())  #将原有规则过滤的包数和字节数保存

        rules_index = self._find_rules_index(new_filter)

        all_chains = [‘:%s‘ % name for name in unwrapped_chains]  #添加完内置链后第一个添加非包装链
        all_chains += [‘:%s-%s‘ % (self.wrap_name, name) for name in chains]  #添加包装链

        # Iterate through all the chains, trying to find an existing
        # match.
        our_chains = []
        for chain in all_chains:
            chain_str = str(chain).strip()

            old = self._find_last_entry(old_filter, chain_str)
            if not old:
                dup = self._find_last_entry(new_filter, chain_str)
            new_filter = [s for s in new_filter if chain_str not in s.strip()]

            # if no old or duplicates, use original chain
            if old or dup:
                chain_str = str(old or dup)
            else:
                # add-on the [packet:bytes]
                chain_str += ‘ - [0:0]‘

            our_chains += [chain_str]  #添加所有的自定义链

        # Iterate through all the rules, trying to find an existing
        # match.
        our_rules = []
        bot_rules = []
        for rule in rules:  #开始添加规则了
            rule_str = str(rule).strip()  #查看下IptablesRule对象后,会看到实现了_str__方法,返回经过处理的字符串
            # Further down, we weed out duplicates from the bottom of the
            # list, so here we remove the dupes ahead of time.

            old = self._find_last_entry(old_filter, rule_str)
            if not old:
                dup = self._find_last_entry(new_filter, rule_str)
            new_filter = [s for s in new_filter if rule_str not in s.strip()]

            # if no old or duplicates, use original rule
            if old or dup:
                rule_str = str(old or dup)
                # backup one index so we write the array correctly
                if not old:
                    rules_index -= 1
            else:
                # add-on the [packet:bytes]
                rule_str = ‘[0:0] ‘ + rule_str

            if rule.top:
                # rule.top == True means we want this rule to be at the top.
                our_rules += [rule_str]
            else:
                bot_rules += [rule_str]

        our_rules += bot_rules  #直接添加规则。规则之间的逻辑顺序其实在创建规则的时候已经给定了(因为已经给定了这个规则所在的链)

        new_filter[rules_index:rules_index] = our_rules #替换规则,注意添加完了后文件中的行数变化了
        new_filter[rules_index:rules_index] = our_chains #替换链,位置是在规则前面

        def _strip_packets_bytes(line):
            # strip any [packet:byte] counts at start or end of lines
            if line.startswith(‘:‘):
                # it‘s a chain, for example, ":neutron-billing - [0:0]"
                line = line.split(‘:‘)[1]
                line = line.split(‘ - [‘, 1)[0]
            elif line.startswith(‘[‘):
                # it‘s a rule, for example, "[0:0] -A neutron-billing..."
                line = line.split(‘] ‘, 1)[1]
            line = line.strip()
            return line

        seen_chains = set()

        def _weed_out_duplicate_chains(line):
            # ignore [packet:byte] counts at end of lines
            if line.startswith(‘:‘):
                line = _strip_packets_bytes(line)
                if line in seen_chains:
                    return False
                else:
                    seen_chains.add(line)

            # Leave it alone
            return True

        seen_rules = set()

        def _weed_out_duplicate_rules(line):
            if line.startswith(‘[‘):
                line = _strip_packets_bytes(line)
                if line in seen_rules:
                    return False
                else:
                    seen_rules.add(line)

            # Leave it alone
            return True

        def _weed_out_removes(line):
            # We need to find exact matches here
            if line.startswith(‘:‘):
                line = _strip_packets_bytes(line)
                for chain in remove_chains:
                    if chain == line:
                        remove_chains.remove(chain)
                        return False
            elif line.startswith(‘[‘):
                line = _strip_packets_bytes(line)
                for rule in remove_rules:
                    rule_str = _strip_packets_bytes(str(rule))
                    if rule_str == line:
                        remove_rules.remove(rule)
                        return False

            # Leave it alone
            return True

        # We filter duplicates.  Go through the chains and rules, letting
        # the *last* occurrence take precedence since it could have a
        # non-zero [packet:byte] count we want to preserve.  We also filter
        # out anything in the "remove" list.
        new_filter.reverse()
        new_filter = [line for line in new_filter
                      if _weed_out_duplicate_chains(line) and
                      _weed_out_duplicate_rules(line) and
                      _weed_out_removes(line)]
        new_filter.reverse()

        # flush lists, just in case we didn‘t find something
        remove_chains.clear()
        for rule in remove_rules:
            remove_rules.remove(rule)  #善后工作

        return new_filter #返回过滤完的规则列表

  

时间: 2024-10-21 14:51:23

OpenStack-Neutron-Fwaas-代码【二】的相关文章

[转] Neutron FWaaS

OpenStack Neutron FWaaS 学习 ( by quqi99 ) 作者:张华  发表于:2013-06-24 版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明 ( http://blog.csdn.net/quqi99 ) 另一篇和防火墙相关的文章,OpenStack中的防火墙 ( by quqi99 ) http://blog.csdn.net/quqi99/article/details/7447233 OpenStack的网络组件已经从

怎样写 OpenStack Neutron 的 Extension (二)

接着之前一篇文章,再来谈谈 Extension 的具体实现问题.我使用的是本地数据库加远程API调用的方法,所以先要定义一下数据库中 myextension 如何存储.首先,我们可以在自己的 plugin 根目录下新建一个 db 文件夹,以及三个文件: - neutron/ - plugins/ - myplugin/ - __init__.py - plugin.py - extensions/ - db/ - __init__.py - db.py - models.py db.py 用来存

深入浅出新一代云网络——VPC中的那些功能与基于OpenStack Neutron的实现(二)

在VPC功能实现第一篇中,简单介绍了一下VPC网络对租户间隔离能力的提升以及基于路由提供的一系列网络功能.在这一篇中,将继续介绍VPC网络中十分重要的一个内容:网络带宽的控制,共享以及分离. 首先是对第一篇中,端口转发功能的样例代码,all-in-one http service 风格的实现. 核心功能: find_router_ip = "ip netns exec qrouter-{router_id} ifconfig |grep -A1 qg- | grep inet | awk '{{

怎样写 OpenStack Neutron 的 Plugin (二)

其实上一篇博文中的内容已经涵盖了大部分写Neutron插件的技术问题,这里主要还遗留了一些有关插件的具体实现的问题. 首先,Neutron对最基本的三个资源:Network, Port 和 Subnet 的基本调用都已经定义好了API接口.如果你的插件也需要用到这些资源,最好直接实现它们的接口.API接口的定义可以再 neutron/neutron_plugin_base_v2.py 这个文件中找到,其中每个参数的作用也有比较详细的介绍.对于用不着的资源,直接放任不管就好了,最多下次不小心调用了

OpenStack Neutron DVR L2 Agent的初步解析(二)

声明: 本博客欢迎转载,但请保留原作者信息! 作者:林凯 团队:华为杭州OpenStack团队 OpenStack Juno版本已正式发布,这是这个开源云平台的10个版本,在Juno版的Neutron模块中真正引入了分布式路由(DVR)的实现,现在就让我们来初步看下分布式路由是怎么样工作的. 在OpenStack Neutron DVR L2 Agent的初步解析 (一)中我们已经知道DVR是怎么样工作的,现在就我们就来看下具体DVR是怎么样创建起来并且生效进行工作的. L2用Plugin与L3

openstack Neutron分析(3)—— neutron-dhcp-agent源码分析

1.neutron dhcp3个主要部件分别为什么?2.dhcp模块包含哪些内容?3.Dnsmasq配置文件是如何创建和更新的?4.DHCP agent的信息存放在neutron数据库的哪个表中? 扩展: neutron-dhcp-agent在neutron的作用是什么? 一.概述 neutron dhcp为租户网络提供DHCP服务,即IP地址动态分配,另外还会提供metadata请求服务. 3个主要的部件:DHCP agent scheduler:负责DHCP agent与network的调度

Neutron - Fwaas配置

Fwaas简介 FWaaS uses iptables to apply firewall policy to all Networking routers within a project.(这些iptables规则存在于router的namespace)FWaaS supports one firewall policy and logical firewall instance per project.(官方介绍,本人翻译水平有限) FWaaS is currently in techni

openstack neutron L3 HA

作者:Liping Mao  发表于:2014-08-20 版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明 最近Assaf Muller写了一篇关于Neutron L3 HA的文章很不错. 建议看原文,地址如下: http://assafmuller.wordpress.com/category/ml2/ 大致翻译如下: L3 Agent Low Availability(L3 agent的低可用性) 目前,在Openstack中,你只能用多个网络节点达到

怎样写 OpenStack Neutron 的 Plugin (一)

鉴于不知道Neutron的人也不会看这篇文章,而知道的人也不用我再啰嗦Neutron是什么东西,我决定跳过Neutron简介,直接爆料. 首先要介绍一下我的开发环境.我没有使用DevStack,而是直接在电脑上安装了三个Virtual Box,然后根据OpenStack的Ubuntu 安装指南部署了一个环境:一个控制节点,一个网络节点和一个计算节点.接下来我会直接在控制节点上修改 <your path>/neutron/ 下面的文件,然后通过重启neutron 的各个service来更新我的修

OpenStack Neutron 之 Load Balance

OpenStack Neutron 之 Load Balance 负载均衡(Load Balance)是 OpenStack Neutron 支持的功能之一.负载均衡能够将网络请求分发到多个实际处理请求的虚机上,这样能有效处理高流量的网络请求,负载均衡在现实中有很多使用场景.本文将基于 Neutron 所提供的负载均衡,介绍其基本概念.实现过程,并验证其功能. Neutron Load Balance 简介 负载均衡(Load Balance)其实早在 OpenStack 的 Grizzly 版