def _parse_snoop_status(is_igmp, vlan_id, data, vlan_name, event_data): ret = True event_data.update({'vlan-id': vlan_id, 'enable': data}) ret = snoop_update_vlan_rules(is_igmp, vlan_name, data) if ret is False: mcast_utils.log_err( 'Failed to %s ebtable snooping rules in kernel for %s ' % ("Add" if data == 1 else "Remove", vlan_name)) return False mcast_utils.log_info('%s ebtable snooping rules in kernel for %s success' % ("Add" if data == 1 else "Remove", vlan_name)) # Disable snooping in kernel. ret = mcast_utils._update_file_system( mcast_utils._get_path_per_vlan_configs(vlan_name, "multicast_snooping"), 0) if ret is False: #When VLAN/bridge gets created,snooping will be disabled, this is just extra . mcast_utils.log_debug('Failed to disable snooping on %s in kernel' % (vlan_name)) return True
def _parse_mcast_snoop_updates_and_publish(data, vlan_info, vlan_id, igmp_events, op): #Parse status, mrouter and route update and publish. vlan_name = vlan_info['cps/key_data']['if/interfaces/interface/name'] try: for k in _snoop_obj_info: for path in _snoop_obj_info[k]['obj_path']: if path in data and _snoop_obj_info[k]['publish_events']: # Publish CPS Events if required event_data = {} mcast_utils.log_info( '%s %s %s for VLAN %d' % ('IGMP' if igmp_events else 'MLD', _snoop_obj_info[k]['event_string'], op, vlan_id)) if (k == 'static_l2_mcast_grp_key'): if (_parse_snoop_routes(vlan_id, vlan_info, op, igmp_events, data[path], event_data)) is False: return False elif (k == 'static_mrouter_key'): if (_parse_snoop_mrouter_ports(vlan_id, vlan_info, op, data[path], event_data)) is False: return False elif (k == 'mcast_snooping'): if (_parse_snoop_status(igmp_events, vlan_id, data[path], vlan_name, event_data)) is False: return False obj = events.MCast_CpsEvents() if event_data: if igmp_events: obj.publish_igmp_events(event_data, op) else: obj.publish_mld_events(event_data, op) mcast_utils.log_info( "Publishing %s %s %s event" % (('IGMP ' if igmp_events else 'MLD '), _snoop_obj_info[k]['event_string'], op)) mcast_utils.log_debug("Publish event data: %s" % (str(event_data))) except Exception as e: mcast_utils.log_err('Exception: %s' % e) return True
def handle_snoop_updates(params): #This handles only the IGMP/MLD snooping "status", "mrouter port" and "route" updates. #This gets called only when kernel snooping functionality is not used and some snooping #application is running. This parses and publishes and does not set/update kernel for mrouter # and route updates. ret = True data = mcast_utils.cps_convert_attr_data(params['change']) mcast_utils.log_debug("Data: %s" % (str(data))) if mcast_utils.igmp_global_enable_key in data: return snoop_update_global_rules( True, data[mcast_utils.igmp_global_enable_key]) elif mcast_utils.mld_global_enable_key in data: return snoop_update_global_rules( False, data[mcast_utils.mld_global_enable_key]) if mcast_utils._keys['vlan_id_key'][ 'igmp'] not in data and mcast_utils._keys['vlan_id_key'][ 'mld'] not in data: mcast_utils.log_err("Missing VLAN ID") return False igmp_events = True if mcast_utils._keys['vlan_id_key']['igmp'] in data: vlan_id_key = mcast_utils._keys['vlan_id_key']['igmp'] else: vlan_id_key = mcast_utils._keys['vlan_id_key']['mld'] igmp_events = False vlan_id = data[vlan_id_key] mcast_utils.log_debug('%s Snoop update received for VLAN %d' % ('IGMP' if igmp_events else 'MLD', vlan_id)) # Get dell-base-if-cmn/if/interfaces/interface object for the given vlan id vlan_info_list = mcast_utils._get_vlan_info(vlan_id) if vlan_info_list is None or len(vlan_info_list) == 0: mcast_utils.log_err('No VLAN Information for VLAN id %d' % vlan_id) return False vlan_info = vlan_info_list[0] ret = _parse_mcast_snoop_updates_and_publish(data, vlan_info, vlan_id, igmp_events, params['operation']) mcast_utils.log_debug('Finish processing snoop updates, ret=%d' % ret) return ret
def remove_ebtables_rules(table, chain, rules): ret = True res = read_ebtable_rules(table, chain) ebtable_prefix = 'ebtables -t ' + table for rule in rules: if rule in res: cmd = (ebtable_prefix + ' -D ' + chain + rule).split() if (mcast_utils.run_command(cmd, res) != 0): ret = False mcast_utils.log_err("Failed to DELETE : %s " % (rule)) else: mcast_utils.log_info("Succesfully DELETED : %s " % (rule)) return ret
def _parse_snoop_mrouter_ports(vlan_id, vlan_info, op, data, event_data): #scan through the leaf-list of mrouter ports. for interface in data: #Validate given interface is VLAN member if mcast_utils.is_intf_vlan_member(vlan_info, interface, vlan_id) is False: if op == "delete": #For delete case, when flow comes here there is a chance that port is # deleted from VLAN and NAS would have cleared multicast info. continue else: mcast_utils.log_err( "interface %s is not VLAN %d member, skip processing" % (str(interface), vlan_id)) return False event_data.update({'vlan-id': vlan_id, 'mrouter-interface': data}) return True
def _parse_snoop_routes(vlan_id, vlan_info, op, igmp_events, group_info, pub_data): for key, val in group_info.items(): if 'group' not in val: mcast_utils.log_err( "Route Event: VLAN %d Group not present, skip processing" % (vlan_id)) continue if 'interface' not in val: mcast_utils.log_err( "Route Event: VLAN %d interface not present, skip processing" % (vlan_id)) continue interface = val['interface'] #Validate given interface is VLAN member if mcast_utils.is_intf_vlan_member(vlan_info, interface, vlan_id) is False: mcast_utils.log_err( "Route Event: interface %s is not VLAN %d member, skip processing" % (str(interface), vlan_id)) if (op != "delete"): return False continue if mcast_utils._is_ip_addr(igmp_events, val['group']): group = val['group'] elif igmp_events is True: group = ba.ba_to_ipv4str('ipv4', val['group']) else: group = ba.ba_to_ipv6str('ipv6', val['group']) pub_data.update({ 'vlan-id': vlan_id, ('group', key, 'interface'): interface, ('group', key, 'address'): group }) if 'source-addr' in val: if mcast_utils._is_ip_addr(igmp_events, val['source-addr']): source = val['source-addr'] elif igmp_events is True: source = ba.ba_to_ipv4str('ipv4', val['source-addr']) else: source = ba.ba_to_ipv6str('ipv6', val['source-addr']) pub_data.update({('group', key, 'source', '0', 'address'): source}) mcast_utils.log_info( "Route event:VLAN %d Interface: %s Group %s Source %s" % (vlan_id, str(interface), group, source)) else: mcast_utils.log_info( "Route Event: VLAN %d Interface %s Source not present, (*, %s) route " % (vlan_id, str(interface), group)) return True
def monitor_VLAN_interface_event(): _vlan_handle = cps.event_connect() cps.event_register(_vlan_handle, _intf_vlan_key) mcast_utils.log_info('monitor_VLAN_interface_event started') while True: vlan_event = cps.event_wait(_vlan_handle) obj = cps_object.CPSObject(obj=vlan_event) if obj is None: mcast_utils.log_err( 'VLAN_MONITOR: Object not present in the event') continue if obj.get_key() != _intf_vlan_key: mcast_utils.log_debug( 'VLAN_MONITOR: Wrong VLAN interface event, ignore') continue try: vlan_name = obj.get_attr_data('if/interfaces/interface/name') # check if if_name is present if vlan_name is None: mcast_utils.log_err( 'VLAN_MONITOR: VLAN name not present in the event') continue if 'operation' in vlan_event: mcast_utils.log_info('VLAN_MONITOR: Received %s %s event' % (vlan_name, vlan_event['operation'])) if (vlan_event['operation'] == 'create'): ret = mcast_utils._update_file_system( mcast_utils._get_path_per_vlan_configs( vlan_name, "multicast_snooping"), 0) if ret is True: mcast_utils.log_info( 'VLAN_MONITOR: Disabled snooping on %s in kernel' % (vlan_name)) else: mcast_utils.log_err( 'VLAN_MONITOR: Failed to disable snooping on %s in kernel' % (vlan_name)) elif (vlan_event['operation'] == 'delete'): #On VLAN deletion, not sure application sends the snoop disable, even if it sends it comes #with VLAN id, so for getting ifname NAS interface may not have VLAN and will fail to get name. #and per VLAN rule in kernel may not get deleted. So here on VLAN deletion the per VLAN IGMP/MLD #rules are deleted. # if (snoop_remove_vlan_rules(True, vlan_name)) is False: mcast_utils.log_debug( 'VLAN_MONITOR: Failed to remove IGMP ebtables rule in kernel for %s' % (vlan_name)) if (snoop_remove_vlan_rules(False, vlan_name)) is False: mcast_utils.log_debug( 'VLAN_MONITOR: Failed to remove MLD ebtables rule in kernel for %s' % (vlan_name)) else: mcast_utils.log_info( 'VLAN_MONITOR: Received event without operation' % (vlan_name)) except Exception as e: mcast_utils.log_err('VLAN_MONITOR: Exception: %s' % e)
def snoop_remove_rule_chain(is_igmp): ret = True res = [] mcast_utils.log_info('Remove %s chain' % (IGMP_CHAIN_NAME if is_igmp else MLD_CHAIN_NAME)) if is_igmp: rule_prefix = 'iptables -t raw ' cmd = (rule_prefix + ' -C ' + igmp_preroute_rule).split() if (mcast_utils.run_command(cmd, res) == 0): cmd = (rule_prefix + ' -D ' + igmp_preroute_rule).split() if (mcast_utils.run_command(cmd, res) != 0): ret = ret and False ret = ret and snoop_delete_iptables_chain(is_igmp, 'raw', IGMP_CHAIN_NAME) mcast_utils.log_info( 'Remove %s chain ret = %d' % (IGMP_CHAIN_NAME if is_igmp else MLD_CHAIN_NAME, ret)) #Delete EBTABLES nat POSTROUTING IGMP rules ret = remove_ebtables_rules(' nat ', ' POSTROUTING ', igmp_global_ebtable_rule) if ret is False: mcast_utils.log_err( 'Failed to Delete EBTABLE IGMP rules from nat POSTROUTING chain' ) return ret ret = snoop_bridge_nf_iptables_disable(is_igmp) if ret is False: mcast_utils.log_err('Failed to disable bridge_nf_call_iptables') return ret else: rule_prefix = 'ip6tables -t raw ' cmd = (rule_prefix + ' -C ' + mld_preroute_rule).split() if (mcast_utils.run_command(cmd, res) == 0): cmd = (rule_prefix + ' -D ' + mld_preroute_rule).split() if (mcast_utils.run_command(cmd, res) != 0): ret = ret and False ret = ret and snoop_delete_iptables_chain(is_igmp, 'raw', MLD_CHAIN_NAME) mcast_utils.log_info( 'Remove %s chain ret = %d' % (IGMP_CHAIN_NAME if is_igmp else MLD_CHAIN_NAME, ret)) #Delete EBTABLES nat POSTROUTING IGMP rules ret = remove_ebtables_rules(' nat ', ' POSTROUTING ', mld_global_ebtable_rule) if ret is False: mcast_utils.log_err( 'Failed to Delete EBTABLE MLD rules from nat POSTROUTING chain' ) return ret ret = snoop_bridge_nf_iptables_disable(is_igmp) if ret is False: mcast_utils.log_err('Failed to disable bridge_nf_call_ip6tables') return ret mcast_utils.log_info( 'All %s global Ebtables/Iptables rules removed with ret = %d' % ('IGMP' if is_igmp else 'MLD', ret)) return ret
def snoop_add_rule_chain(is_igmp): ret = True res = [] mcast_utils.log_debug('Create chain: %d' % (is_igmp)) #EBTABLES: #For each snoop disabled VLAN's, received IGMP/MLD packets are marked #and dropped in iptables raw table IGMPSNOOP/MLDSNOOP chain. # Here: #1. Create IGMPSNOOP/MLDSNOOP chain in iptables raw table to check the # IGMP/MLD packet types and drop all the iGMP/MLD packets other than query # for enabled VLANs. For enabled VLAN's snoop application will decide what # to do with the packet. #2. Create a Rule in iptables raw table PREROUTING chain to catch # marked (snooping enabled VLAN's) IGMP/MLD packets and redirect to # IGMPSNOOOP/MLDSNOOP chain if is_igmp: ret = snoop_create_iptables_chain(is_igmp, 'raw', IGMP_CHAIN_NAME) if ret is False: mcast_utils.log_err( 'Failed to create/add iptables rules to %s chain' % (IGMP_CHAIN_NAME)) return ret # Add PREROUTING rule rule_prefix = 'iptables -t raw ' cmd = (rule_prefix + ' -C ' + igmp_preroute_rule).split() if (mcast_utils.run_command(cmd, res) != 0): cmd = (rule_prefix + ' -A ' + igmp_preroute_rule).split() if (mcast_utils.run_command(cmd, res) != 0): ret = ret and False if ret is False: mcast_utils.log_err( 'Failed to add iptables rules to PREROUTING chain') return ret #Add EBTABLES nat POSTROUTING IGMP rules ret = add_ebtable_rules(' nat ', ' POSTROUTING ', igmp_global_ebtable_rule) if ret is False: mcast_utils.log_err( 'Failed to add IGMP EBTABLE rules to nat POSTROUTING chain') return ret ret = snoop_bridge_nf_iptables_enable(is_igmp) if ret is False: mcast_utils.log_err('Failed to enable bridge_nf_call_iptables') return ret else: ret = snoop_create_iptables_chain(is_igmp, 'raw', MLD_CHAIN_NAME) if ret is False: mcast_utils.log_err( 'Failed to create/add ip6tables rules to %s chain' % (MLD_CHAIN_NAME)) return ret # Add PREROUTING rule rule_prefix = 'ip6tables -t raw ' cmd = (rule_prefix + ' -C ' + mld_preroute_rule).split() if (mcast_utils.run_command(cmd, res) != 0): cmd = (rule_prefix + ' -A ' + mld_preroute_rule).split() if (mcast_utils.run_command(cmd, res) != 0): ret = ret and False if ret is False: mcast_utils.log_err( 'Failed to add ip6tables rules to PREROUTING chain') return ret mcast_utils.log_debug('%s chain created and rules added succesfully' % (IGMP_CHAIN_NAME if is_igmp else MLD_CHAIN_NAME)) #Add EBTABLES nat POSTROUTING MLD rules ret = add_ebtable_rules(' nat ', ' POSTROUTING ', mld_global_ebtable_rule) if ret is False: mcast_utils.log_err( 'Failed to add MLD EBTABLE rules to nat POSTROUTING chain') return ret ret = snoop_bridge_nf_iptables_enable(is_igmp) if ret is False: mcast_utils.log_err('Failed to enable bridge_nf_call_ip6tables') return ret mcast_utils.log_info( 'All %s global Ebtables/Iptables created and rules added succesfully' % ('IGMP' if is_igmp else 'MLD')) return ret