neutron代码解析之l3-agent的启动

前言

每个 L3 Agent 运行在一个 network namespace 中,以 qrouter-<router-UUID>命名。网络节点如果不支持 Linux namespace 的,只能运行一个 Virtual Router。通过配置项use_namespaces = True开启namespace。本文只做单纯的分析代码,研究了neutron的l3-agent代码(m版本),代码路径为/neutron/agent/l3/agent.py。主要的类是:

  • class L3PluginApi(object): l3-agent的rpc接口,用于回复和查询l3-plugin的。
  • class L3NATAgent(firewall_l3_agent.FWaaSL3AgentRpcCallback,ha.AgentMixin,dvr.AgentMixin,manager.Manager): l3-agent实现类。

主要来说说L3NATAgent。该类在运行的时候,会启动两个周期任务:

  • periodic_sync_routers_task:周期性获取router列表,并将需要操作的router加入到队列中;
  • _process_routers_loop:从上个任务中获取队列中的router,并进行处理(增删和更新)。
    接下来依次分析这两个任务。

periodic_sync_routers_task

注意该类继承了FWaaSL3AgentRpcCallback和Manager两个类。Manager类里有个方法periodic_tasks,运行的是父类的方法run_periodic_tasks

class Manager(periodic_task.PeriodicTasks):
       
    # Set RPC API version to 1.0 by default.
    target = oslo_messaging.Target(version='1.0')
          
    def periodic_tasks(self, context, raise_on_error=False):
        self.run_periodic_tasks(context, raise_on_error=raise_on_error)

在neutron/service.py里的类Service,启动start的时候,会加载Manager的periodic_tasks方法,并设置周期时间:

class Service(n_rpc.Service):
       
    def start(self):
        self.manager.init_host()
        super(Service, self).start()
        if self.report_interval:
            pulse = loopingcall.FixedIntervalLoopingCall(self.report_state)
            pulse.start(interval=self.report_interval,initial_delay=self.report_interval)
            self.timers.append(pulse)
           
        if self.periodic_interval:
            if self.periodic_fuzzy_delay:
                initial_delay = random.randint(0, self.periodic_fuzzy_delay)
            else:
                initial_delay = None
          
            periodic = loopingcall.FixedIntervalLoopingCall(self.periodic_tasks)
            periodic.start(interval=self.periodic_interval,initial_delay=initial_delay)
            self.timers.append(periodic)
        self.manager.after_start()
            
    def periodic_tasks(self, raise_on_error=False):
        """Tasks to be run at a periodic interval."""
        ctxt = context.get_admin_context()
        self.manager.periodic_tasks(ctxt, raise_on_error=raise_on_error)

然后说回L3NATAgent类,它定义了一个方法periodic_sync_routers_task,被@periodic_task.periodic_task(spacing=1, run_immediately=True)进行了装饰,可以理解为间隔时间为1秒运行一次任务。periodic_task是oslo_service/periodic_task.py里的装饰器方法,用于将被装饰的方法声明为一个周期性任务;而该文件里还有一个方法也就是上文提到的run_periodic_tasks,用于运行所有的周期任务:

    # NOTE(kevinbenton): this is set to 1 second because the actual interval
    # is controlled by a FixedIntervalLoopingCall in neutron/service.py that
    # is responsible for task execution.
    @periodic_task.periodic_task(spacing=1, run_immediately=True)
    def periodic_sync_routers_task(self, context):
    ...

        try:
            with self.namespaces_manager as ns_manager:
                self.fetch_and_sync_all_routers(context, ns_manager)

periodic_sync_routers_task执行了一个任务fetch_and_sync_all_routers,即是通过l3-plugin RPC获取到router列表,然后将需要进行操作的router加入到 _queue 中。理解了这个,就能明白接下来的一个线程循环任务 _process_routers_loop。

_process_routers_loop

在l3-agent开始启动过程after_start中,还会启动一个线程来循环执行一个任务_process_routers_loop

    def after_start(self):
        # Note: the FWaaS' vArmourL3NATAgent is a subclass of L3NATAgent. It
        # calls this method here. So Removing this after_start() would break
        # vArmourL3NATAgent. We need to find out whether vArmourL3NATAgent
        # can have L3NATAgentWithStateReport as its base class instead of
        # L3NATAgent.
        eventlet.spawn_n(self._process_routers_loop)
        LOG.info(_LI("L3 agent started"))
    def _process_routers_loop(self):
        LOG.debug("Starting _process_routers_loop")
        pool = eventlet.GreenPool(size=8)
        while True:
            pool.spawn_n(self._process_router_update)

再来看看方法_process_router_update,方法一开始就会通过_queue.each_update_to_next_router从上一个任务的队列里获取需要进行操作的router信息。然后会针对不通的action,进行一些处理,真正进行router操作的是_process_router_if_compatible:

    def _process_router_update(self):
        for rp, update in self._queue.each_update_to_next_router():
            LOG.debug("Starting router update for %s, action %s, priority %s",
                      update.id, update.action, update.priority)
            if update.action == queue.PD_UPDATE:
                self.pd.process_prefix_update()
                LOG.debug("Finished a router update for %s", update.id)
                continue
            router = update.router
            ......
            try:
                self._process_router_if_compatible(router)
            ......
      
            LOG.debug("Finished a router update for %s", update.id)
            rp.fetched_and_processed(update.timestamp)

_process_router_if_compatible方法的主要实现,在最后:

    def _process_router_if_compatible(self, router):
        ......
        if router['id'] not in self.router_info:
            self._process_added_router(router)
        else:
            self._process_updated_router(router)

_process_updated_router为例:

    def _process_updated_router(self, router):
        ri = self.router_info[router['id']]
        ri.router = router
        registry.notify(resources.ROUTER, events.BEFORE_UPDATE,self, router=ri)
        ri.process(self)
        registry.notify(resources.ROUTER, events.AFTER_UPDATE, self, router=ri)

针对router的所有操作都在neutron/agent/l3/router_info.py中的方法process里。具体细节在这里就不做分析了,包括对external-port,internal-port和floating ip的一系列处理。

个人分析,欢迎指正,若转载请注明出处
欢迎访问我的主页

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容