neutron-metering解读分析

metering简介

metering是l3层流量监控的插件,通过统计iptables规则的流量计数达到流量监控的目的。
iptables流量统计
与iptables类似,创建metering label即创建一条自定义链,这条链被Forward表引用,针对某个ip创建metering label rule则生成相应的规则,进出方向的流量会留下它的痕迹。

metering配置

  1. 路径/etc/neutron,新增配置文件metering_agent.ini
# metering_agent.ini
interface_driver =neutron.agent.linux.interface.OVSInterfaceDriver
driver = neutron.services.metering.drivers.iptables.iptables_driver.IptablesMeteringDriver
  1. 文件/etc/neutron/neutron.conf,新增services_plugins
    新增metering
  2. metering_agnet是一个单独的进程,负责与qrouter交互,创建iptables规则,执行命令:
/var/lib/openstack/bin/python /var/lib/openstack/bin/neutron-metering-agent --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/metering_agent.ini

metering_plugin

  1. API路径在neutron_lib/api/definitions
  2. neutron-server接收请求后交给plugin处理,路径neutron/services/metering/metering_plugin.py
  3. MeteringPlugin类存在以下方法:
def start_rpc_listeners
def create_metering_label
def delete_metering_label
def create_metering_label_rule
def delete_metering_label_rule
  1. 这些方法都按照一定的格式执行,先调用metering_plugin操作db,在通过rpc发送消息让agent端处理
def create_metering_label(self, context, metering_label):
    label = super(MeteringPlugin, self).create_metering_label(
        context, metering_label)

    data = self.get_sync_data_metering(context)
    self.meter_rpc.add_metering_label(context, data)

    return label
  1. create_metering_label 为例,MeteringPlugin调用父类metering_db.MeteringDbMixin的方法create_metering_label 创建label的db,get_sync_data_metering 调用MeteringDbMixin的方法同步router数据,拿到的data是一个字典,对象是routers,每个router都带上了_metering_label 的标签
  2. add_metering_label 则通过rpc消息队列发送给metering_agent端,让agent端执行实际的操作,rpc的接口定义在neutron/api/rpc/agentnotifiers/metering_rpc_agent_api.py

metering_agent

agent端可以分为三块主要内容:

  1. 同步router、labels,labelrules的内容,进程拉起时会同步一次qrouter iptables的自定义链和规则,往后每隔一段时间会再次获取routers的内容,更新缓存
def _sync_router_namespaces(self, context, routers):
   LOG.debug("Sync router namespaces")
   return self._invoke_driver(context, routers, 'sync_router_namespaces')
  1. 接受来自metering_plugin的请求,创建/删除labels、rules
    接受来自metering_plugin的请求
  2. metering_agent调用driver获取iptables的流量监控信息,并发送给上层应用。原版的openstack通过ceilometer获取metering收集的流量信息并对外展示,但各大厂商可以设计自己的流量监控方案,例如通过消息队列kafka、rabbitmq等将监控信息转发到自己的流量监控平台上
    发送流量监控消息
    metering_agent的代码都遵循同一个范式,即收到上层的消息后,经过处理或者不处理,去调用_invoke_driver 的函数,这其实是个调用driver的通用方法,用户可以定义自己的driver,并在配置文件中指定,agent拉起时会自动加载相应的driver,而_invoke_driver 的调用则会拉起对应driver中的方法
def _invoke_driver(self, context, meterings, func_name):
    try:
        return getattr(self.metering_driver, func_name)(context, meterings)
    except AttributeError:
        LOG.exception("Driver %(driver)s does not implement %(func)s",
                      {'driver': self.conf.driver,
                       'func': func_name})
    except RuntimeError:
        LOG.exception("Driver %(driver)s:%(func)s runtime error",
                      {'driver': self.conf.driver,
                       'func': func_name})

self.metering_driver 是已经加载好的驱动,通过获取对应的func_name 映射到相应的函数体,并执行

metering driver

  1. neutron(R版本)中暂时只实现了iptables driver,路径在neutron/services/metering/drivers/iptables
  2. neutron metering其实存在第二种noop driver,以我浅薄的认知目前还不知道noop具体是个啥玩意,源码中也没有实现具体的方法,但是给我们新增driver打了个样
  3. 以添加rule为例,_add_metering_label_rule 直接调用方法_process_metering_rule_action
def _process_metering_rule_action(self, router, action):
   rm = self.routers.get(router['id'])
   if not rm:
       return

   ext_dev, ext_snat_dev = self.get_external_device_names(rm)
   for (im, dev) in [(rm.iptables_manager, ext_dev),
                     (rm.snat_iptables_manager, ext_snat_dev)]:
       if im and dev:
           self._process_metering_rule_action_based_on_ns(
               router, action, dev, im)
  1. get_external_device_names 是获取所需监控的qrouter内的网络设备,这一点需要注意,legacy router、ha router以及dvr router中相应的qrouter网关前缀未必是相同的,虽然源码中对qrouter内的网络设备设置唯一前缀“qr-”,但这一点的确应该注意。如果网络设备前缀并非都是“qr-”,可能会导致rule无法收集到监控数据
  2. dvr router与ha router应该分别区分
  3. 获取到网络设备名字后,调用_process_metering_rule_action_based_on_ns 方法,首先分析router带下来的_metering_labels 字段,分析label是否发生变化,如果发生变化则同步一次,并更新缓存,如果rule字段存在,则调用具体的方法更新rule
def _add_rule_to_chain(self, ext_dev, rule, im,
                       label_chain, rules_chain):
    ipt_rule = self._prepare_rule(ext_dev, rule, label_chain)
    if rule['excluded']:
        im.ipv4['filter'].add_rule(rules_chain, ipt_rule,
                                   wrap=False, top=True)
    else:
        im.ipv4['filter'].add_rule(rules_chain, ipt_rule,
                                   wrap=False, top=False)

def _prepare_rule(self, ext_dev, rule, label_chain):
    remote_ip = rule['remote_ip_prefix']
    if rule['direction'] == 'egress':
        dir_opt = '-s %s -o %s' % (remote_ip, ext_dev)
    else:
        dir_opt = '-d %s -i %s' % (remote_ip, ext_dev)

    if rule['excluded']:
        ipt_rule = '%s -j RETURN' % dir_opt
    else:
        ipt_rule = '%s -j %s' % (dir_opt, label_chain)
    return ipt_rule

新增规则是以字符串的方式生成,两个方向:出方向egress,入方向ingress,不同的方向生成的规则也有差异,最终调用neutron/agent/linux/iptables_mamager.py执行命令行

  1. 收集数据的方法是get_traffic_counters ,这个方法调用iptables_manager类的get_traffic_counters 执行以下命令
sudo ip netns exec qrouter-namespace-id iptables -t filter -L chain-name -n -v -x -w xlock_wait_time -Z
  1. get_traffic_counters 通过参数zero开启每次计数后归零的功能,因此metering生成的规则流量计数会定时清零
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值