dhcp_monitor 是 VDSM 的 network 模块中的一部分,这里单独记录下源码分析。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 def initialize_monitor(cif): global _monitor_instance try: monitor = Monitor.instance() monitor.add_handler(lambda event: _dhcp_event_handler(cif, event)) monitor.start() except Exception as e: _monitor_instance = None raise e Monitor 的 add_handler 接收了一个 event 作为 handler,然后在 monitor 的 init 函数中会通过 serve_forever 去执行这个方法 def handle_event(self, event): for handler in self._handlers: handler(event) def serve_forever(self): for event in self._nl_monitor: self.handle_event(event)
对应到前面,执行这个 _dhcp_event_handler,其中 address.address, address.prefixlen 对应 ip address 和 network mask。这里的 address 和 iface 是从 event 中读取的,EventField.IFACE 和 EventField.ADDRESS 是常量:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class EventField(object): class Scope(object): KEY = 'scope' GLOBAL = 'global' class Event(object): KEY = 'event' NEW_ADDR = 'new_addr' class Family(object): KEY = 'family' IPV4 = 'inet' IPV6 = 'inet6' ADDRESS = 'address' IFACE = 'label'
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 def _dhcp_event_handler(cif, event): if not _is_valid_event(event): return pool = MonitoredItemPool.instance() iface = event[EventField.IFACE] family = _get_event_family(event.get(EventField.Family.KEY)) address = IPAddressData(event[EventField.ADDRESS], iface) item = (iface, family) if not pool.is_item_in_pool(item): logging.warning( 'Nic %s is not configured for IPv%s monitoring.', iface, family ) return if family == 4: add_dynamic_source_route_rules( iface, address.address, address.prefixlen ) cif.notify('|net|host_conn|no_id') pool.remove(item)
然后 add_dynamic_source_route_rules -> _setup_desired_state -> setup -> state_apply, state_apply 是 libnmstate 的方法,也就是设置网络的期望状态(声明式网络管理器API),也就是说,这里提交了该物理机期望的网络状态,提交给 nmstate,由 nmstate 去设置。
1 2 3 4 5 6 7 8 9 def add_dynamic_source_route_rules(next_hop, ipaddr, mask): if not _should_add_source_route_rules(next_hop): return _setup_desired_state( generate_dynamic_source_route_rule_state( next_hop, ipaddr, mask ).state() )
generate_dynamic_source_route_rule_state 用于生成网络配置信息。
1 2 3 def generate_dynamic_source_route_rule_state(next_hop, ipaddr, mask): helper = SourceRouteHelper(next_hop, ipaddr, mask, None) return NetworkingState(route_rules_state=helper.rules_state())
查看helper ,目前只支持 IPv4 的 source routing
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 # FIXME: Currently we are supporting only IPv4 source routing class SourceRouteHelper(object): def __init__(self, next_hop, ipaddr, mask, gateway): self._next_hop = next_hop self._ipaddr = ipaddr self._mask = mask self._gateway = gateway self._table_id = generate_table_id(next_hop) if next_hop else None self._network = self._parse_network() def _parse_network(self): if not self._ipaddr or not self._mask: return None return str( ipaddress.ip_interface(f'{self._ipaddr}/{self._mask}').network )
最后调用 NetworkingState 生成了一个 networkingstate 对象,里面设置了 ip,mask,gateway。 此时 NetworkingState 对象的其它方法就可以通过 network api 去调用,去修改 vdsm host 网络的信息。比如 lib/vdsm/network/nmstate/state.py 中的 update_mtu() 方法,在 lib/vdsm/network/nmstate/api.py 中的 generate_state 接口调用,而 generate_state 在 lib/vdsm/network/netswitch/configurator.py 的 _setup_nmstate 中调用,一直到最上层,就是 setupNetworks 接口。
Cif 的 notify 方法位置: lib/vdsm/clientIF.py 中的 notify
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 def notify(self, event_id, params=None): """ Send notification using provided subscription id as event_id and a dictionary as event body. Before sending there is notify_time added on top level to the dictionary. Please consult event-schema.yml in order to build an appropriate event. https://github.com/oVirt/vdsm/blob/master/lib/api/vdsm-events.yml Args: event_id (string): unique event name params (dict): event content """ if not params: params = {} if not self.ready: self.log.warning('Not ready yet, ignoring event %r args=%r', event_id, params) return json_binding = self.servers['jsonrpc'] def _send_notification(message): json_binding.reactor.server.send( message, config.get('addresses', 'event_queue')) try: notification = Notification(event_id, _send_notification, json_binding.bridge.event_schema) notification.emit(params) self.log.debug("Sending notification %s with params %s ", event_id, params) except KeyError: self.log.warning("Attempt to send an event when jsonrpc binding" " not available")
跟网络相关的,很多地方使用 event.get() 获取的数据,_event 是从 _nl_monitor 中获取的
1 2 3 4 5 6 7 8 9 10 11 lib/vdsm/network/dhcp_monitor.py def add_handler(self, handler): self._handlers.append(handler) def handle_event(self, event): for handler in self._handlers: handler(event) def serve_forever(self): for event in self._nl_monitor: self.handle_event(event)
nl_monitor 实际上是 lib/vdsm/network/netlink/monitor.py 中的 Monitor,而这个 Monitor 实际上是 netlink 的 monitor,跟 libnl.GROUPS 对应。netlink 参考 Netlink 和 libnl 基础