@@ -174,6 +174,7 @@ def _build_flow_expr(**kwargs):
174174 dl_dst = 'dl_dst' in kwargs and ",dl_dst=%s" % kwargs ['dl_dst' ] or ''
175175 nw_src = 'nw_src' in kwargs and ",nw_src=%s" % kwargs ['nw_src' ] or ''
176176 nw_dst = 'nw_dst' in kwargs and ",nw_dst=%s" % kwargs ['nw_dst' ] or ''
177+ table = 'table' in kwargs and ",table=%s" % kwargs ['table' ] or ''
177178 proto = 'proto' in kwargs and ",%s" % kwargs ['proto' ] or ''
178179 ip = ('nw_src' in kwargs or 'nw_dst' in kwargs ) and ',ip' or ''
179180 flow = (flow + in_port + dl_type + dl_src + dl_dst +
@@ -217,3 +218,228 @@ def del_all_flows(bridge):
217218def del_port (bridge , port ):
218219 delPort = [VSCTL_PATH , "del-port" , bridge , port ]
219220 do_cmd (delPort )
221+
222+
223+ def get_network_id_for_vif (vif_name ):
224+ domain_id , device_id = vif_name [3 :len (vif_name )].split ("." )
225+ dom_uuid = do_cmd ([XE_PATH , "vm-list" , "dom-id=%s" % domain_id , "--minimal" ])
226+ vif_uuid = do_cmd ([XE_PATH , "vif-list" , "vm-uuid=%s" % dom_uuid , "device=%s" % device_id , "--minimal" ])
227+ vnet = do_cmd ([XE_PATH , "vif-param-get" , "uuid=%s" % vif_uuid , "param-name=other-config" ,
228+ "param-key=cloudstack-network-id" ])
229+ return vnet
230+
231+ def get_network_id_for_tunnel_port (tunnelif_name ):
232+ vnet = do_cmd ([VSCTL_PATH , "get" , "interface" , tunnelif_name , "options:cloudstack-network-id" ])
233+ return vnet
234+
235+ def clear_flooding_rules_for_port (bridge , ofport ):
236+ del_flows (bridge , in_port = ofport , table = 2 )
237+
238+ def add_flooding_rules_for_port (bridge , in_ofport , out_ofports ):
239+ action = "" .join ("output:%s," % ofport for ofport in out_ofports )[:- 1 ]
240+ add_flow (bridge , priority = 1100 , in_port = in_ofport , table = 1 , actions = action )
241+
242+ def get_ofport_for_vif (vif_name ):
243+ return do_cmd ([VSCTL_PATH , "get" , "interface" , vif_name , "ofport" ])
244+
245+ def get_macaddress_of_vif (vif_name ):
246+ domain_id , device_id = vif_name [3 :len (vif_name )].split ("." )
247+ dom_uuid = do_cmd ([XE_PATH , "vm-list" , "dom-id=%s" % domain_id , "--minimal" ])
248+ vif_uuid = do_cmd ([XE_PATH , "vif-list" , "vm-uuid=%s" % dom_uuid , "device=%s" % device_id , "--minimal" ])
249+ mac = do_cmd ([XE_PATH , "vif-param-get" , "uuid=%s" % vif_uuid , "param-name=MAC" ])
250+ return mac
251+
252+ def get_vif_name_from_macaddress (macaddress ):
253+ vif_uuid = do_cmd ([XE_PATH , "vif-list" , "MAC=%s" % macaddress , "--minimal" ])
254+ vif_device_id = do_cmd ([XE_PATH , "vif-param-get" , "uuid=%s" % vif_uuid , "param-name=device" ])
255+ vm_uuid = do_cmd ([XE_PATH , "vif-param-get" , "uuid=%s" % vif_uuid , "param-name=vm-uuid" ])
256+ vm_domain_id = do_cmd ([XE_PATH , "vm-param-get" , "uuid=%s" % vm_uuid , "param-name=dom-id" ])
257+ return "vif" + vm_domain_id + "." + vif_device_id
258+
259+ def add_mac_lookup_table_entry (bridge , mac_address , out_of_port ):
260+ add_flow (bridge , priority = 1100 , dl_dst = mac_address , table = 1 , actions = "output:%s" % out_of_port )
261+
262+ def delete_mac_lookup_table_entry (bridge , mac_address ):
263+ del_flows (bridge , dl_dst = mac_address , table = 1 )
264+
265+ def add_ip_lookup_table_entry (bridge , ip , dst_tier_gateway_mac , dst_vm_mac ):
266+ action_str = "mod_dl_sr:%s" % dst_tier_gateway_mac + ",mod_dl_dst:%s" % dst_vm_mac + ",resubmit(,5)"
267+ addflow = [OFCTL_PATH , "add-flow" , bridge , "table=4" , "nw_dst=%s" % ip , "actions=%s" % action_str ]
268+ do_cmd (addflow )
269+
270+ def get_vms_on_host (vpc , host_id ):
271+ all_vms = vpc .vms
272+ vms_on_host = []
273+ for vm in all_vms :
274+ if vm .hostid == host_id :
275+ vms_on_host .append (vm )
276+ return vms_on_host
277+
278+ def get_network_details (vpc , network_uuid ):
279+ tiers = vpc .tiers
280+ for tier in tiers :
281+ if tier .networkuuid == network_uuid :
282+ return tier
283+ return None
284+
285+ class jsonLoader (object ):
286+ def __init__ (self , obj ):
287+ for k in obj :
288+ v = obj [k ]
289+ if isinstance (v , dict ):
290+ setattr (self , k , jsonLoader (v ))
291+ elif isinstance (v , (list , tuple )):
292+ if len (v ) > 0 and isinstance (v [0 ], dict ):
293+ setattr (self , k , [jsonLoader (elem ) for elem in v ])
294+ else :
295+ setattr (self , k , v )
296+ else :
297+ setattr (self , k , v )
298+
299+ def __getattr__ (self , val ):
300+ if val in self .__dict__ :
301+ return self .__dict__ [val ]
302+ else :
303+ return None
304+
305+ def __repr__ (self ):
306+ return '{%s}' % str (', ' .join ('%s : %s' % (k , repr (v )) for (k , v )
307+ in self .__dict__ .iteritems ()))
308+
309+ def __str__ (self ):
310+ return '{%s}' % str (', ' .join ('%s : %s' % (k , repr (v )) for (k , v )
311+ in self .__dict__ .iteritems ()))
312+
313+ def configure_bridge_for_network_topology (bridge , this_host_id , json_config ):
314+ vpconfig = jsonLoader (json .loads (json_config )).vpc
315+
316+ if vpconfig is None :
317+ logging .debug ("WARNING:Can't find VPC info in json config file" )
318+ return "FAILURE:IMPROPER_JSON_CONFG_FILE"
319+
320+ # get the list of Vm's in the VPC from the JSON config
321+ this_host_vms = get_vms_on_host (vpconfig , this_host_id )
322+
323+ for vm in this_host_vms :
324+ for nic in vm .nics :
325+ mac_addr = nic .macaddress
326+ ip = nic .ipaddress
327+ vif_name = get_vif_name_from_macaddress (mac_addr )
328+ of_port = get_ofport_for_vif (vif_name )
329+ network = get_network_details (vpconfig , nic .networkuuid )
330+
331+ # Add flow rule in L2 look up table, if the destination mac = MAC of the nic send packet on the found OFPORT
332+ add_mac_lookup_table_entry (bridge , mac_addr , of_port )
333+
334+ # Add flow rule in L3 look up table: if the destination IP = VM's IP then modify the packet
335+ # to set DST MAC = VM's MAC, SRC MAC=tier gateway MAC and send to egress table
336+ add_ip_lookup_table_entry (bridge , ip , network .gatewaymac , mac_addr )
337+
338+ # Add flow entry to send with intra tier traffic from the NIC to L2 lookup path)
339+ addflow = [OFCTL_PATH , "add-flow" , bridge , "table=0" , "in_port=%s" % of_port ,
340+ "nw_dst=%s" % network .cidr , "actions=resubmit(,1)" ]
341+ do_cmd (addflow )
342+
343+ #add flow entry to send inter-tier traffic from the NIC to egress ACL table(to L3 lookup path)
344+ addflow = [OFCTL_PATH , "add-flow" , bridge , "table=0" , "in_port=%s" % of_port ,
345+ "dl_dst=%s" % network .gatewaymac , "nw_dst=%s" % vpconfig .cidr , "actions=resubmit(,3)" ]
346+ do_cmd (addflow )
347+
348+ # get the list of hosts on which VPC spans from the JSON config
349+ vpc_spanning_hosts = vpconfig .hosts
350+
351+ for host in vpc_spanning_hosts :
352+ if this_host_id == host .hostid :
353+ continue
354+ other_host_vms = get_vms_on_host (vpconfig , host .hostid )
355+ for vm in other_host_vms :
356+ for nic in vm .nics :
357+ mac_addr = nic .macaddress
358+ ip = nic .ipaddress
359+ network = get_network_details (vpconfig , nic .networkuuid )
360+ gre_key = network .grekey
361+
362+ # generate tunnel name from tunnel naming convention
363+ tunnel_name = "t%s-%s-%s" % (gre_key , this_host_id , host .hostid )
364+ of_port = get_ofport_for_vif (tunnel_name )
365+
366+ # Add flow rule in L2 look up table, if the destination mac = MAC of the nic send packet tunnel port
367+ add_mac_lookup_table_entry (bridge , mac_addr , of_port )
368+
369+ # Add flow tule in L3 look up table: if the destination IP = VM's IP then modify the packet
370+ # set DST MAC = VM's MAC, SRC MAC=tier gateway MAC and send to egress table
371+ add_ip_lookup_table_entry (bridge , ip , network .gatewaymac , mac_addr )
372+
373+ return "SUCCESS: successfully configured bridge as per the VPC topology"
374+
375+ def get_acl (vpcconfig , required_acl_id ):
376+ acls = vpcconfig .acls
377+ for acl in acls :
378+ if acl .id == required_acl_id :
379+ return acl
380+ return None
381+
382+ def configure_ovs_bridge_for_routing_policies (bridge , json_config ):
383+ vpconfig = jsonLoader (json .loads (json_config )).vpc
384+
385+ if vpconfig is None :
386+ logging .debug ("WARNING:Can't find VPC info in json config file" )
387+ return "FAILURE:IMPROPER_JSON_CONFG_FILE"
388+
389+ # First flush current egress ACL's before re-applying the ACL's
390+ del_flows (bridge , table = 3 )
391+
392+ egress_rules_added = False
393+ ingress_rules_added = False
394+
395+ tiers = vpconfig .tiers
396+ for tier in tiers :
397+ tier_cidr = tier .cidr
398+ acl = get_acl (vpconfig , tier .aclid )
399+ acl_items = acl .aclitems
400+
401+ for acl_item in acl_items :
402+ number = acl_item .number
403+ action = acl_item .action
404+ direction = acl_item .direction
405+ source_port_start = acl_item .sourceportstart
406+ source_port_end = acl_item .sourceportend
407+ protocol = acl_item .protocol
408+ source_cidrs = acl_item .sourcecidrs
409+ acl_priority = 1000 + number
410+ for source_cidr in source_cidrs :
411+ if direction is "ingress" :
412+ ingress_rules_added = True
413+ # add flow rule to do action (allow/deny) for flows where source IP of the packet is in
414+ # source_cidr and destination ip is in tier_cidr
415+ port = source_port_start
416+ while (port < source_port_end ):
417+ if action is "deny" :
418+ add_flow (bridge , priority = acl_priority , table = 5 , nw_src = source_cidr , nw_dst = tier_cidr , tp_dst = port ,
419+ nw_proto = protocol , actions = 'drop' )
420+ if action is "allow" :
421+ add_flow (bridge , priority = acl_priority ,table = 5 , nw_src = source_cidr , nw_dst = tier_cidr , tp_dst = port ,
422+ nw_proto = protocol , actions = 'resubmit(,1)' )
423+ port = port + 1
424+
425+ elif direction in "egress" :
426+ egress_rules_added = True
427+ # add flow rule to do action (allow/deny) for flows where destination IP of the packet is in
428+ # source_cidr and source ip is in tier_cidr
429+ port = source_port_start
430+ while (port < source_port_end ):
431+ if action is "deny" :
432+ add_flow (bridge , priority = acl_priority , table = 5 , nw_src = tier_cidr , nw_dst = source_cidr , tp_dst = port ,
433+ nw_proto = protocol , actions = 'drop' )
434+ if action is "allow" :
435+ add_flow (bridge , priority = acl_priority , table = 5 , nw_src = tier_cidr , nw_dst = source_cidr , tp_dst = port ,
436+ nw_proto = protocol , actions = 'resubmit(,1)' )
437+ port = port + 1
438+
439+ if egress_rules_added is False :
440+ # add a default rule in egress table to forward packet to L3 lookup table
441+ add_flow (bridge , priority = 0 , table = 3 , actions = 'resubmit(,4)' )
442+
443+ if ingress_rules_added is False :
444+ # add a default rule in egress table drop packets
445+ add_flow (bridge , priority = 0 , table = 5 , actions = 'drop' )
0 commit comments