@@ -344,8 +344,139 @@ def get_acl(vpcconfig, required_acl_id):
344344 return acl
345345 return None
346346
347- # Configures the bridge created for a VPC enabled for distributed routing. Management server sends VPC physical topology
348- # details. Based on the VPC physical topology L2 lookup table and L3 lookup tables are updated by this function.
347+ def check_tunnel_exists (bridge , tunnel_name ):
348+ res = do_cmd ([VSCTL_PATH , "port-to-br" , tunnel_name ])
349+ return res == bridge
350+
351+ def create_tunnel (bridge , remote_ip , gre_key , src_host , dst_host , network_uuid ):
352+
353+ logging .debug ("Creating tunnel from host %s" % src_host + " to host %s" % dst_host + " with GRE key %s" % gre_key )
354+
355+ res = check_switch ()
356+ if res != "SUCCESS" :
357+ logging .debug ("Openvswitch running: NO" )
358+ return "FAILURE:%s" % res
359+
360+ # We need to keep the name below 14 characters
361+ # src and target are enough - consider a fixed length hash
362+ name = "t%s-%s-%s" % (gre_key , src_host , dst_host )
363+
364+ # Verify the xapi bridge to be created
365+ # NOTE: Timeout should not be necessary anymore
366+ wait = [VSCTL_PATH , "--timeout=30" , "wait-until" , "bridge" ,
367+ bridge , "--" , "get" , "bridge" , bridge , "name" ]
368+ res = do_cmd (wait )
369+ if bridge not in res :
370+ logging .debug ("WARNING:Can't find bridge %s for creating " +
371+ "tunnel!" % bridge )
372+ return "FAILURE:NO_BRIDGE"
373+ logging .debug ("bridge %s for creating tunnel - VERIFIED" % bridge )
374+ tunnel_setup = False
375+ drop_flow_setup = False
376+ try :
377+ # Create a port and configure the tunnel interface for it
378+ add_tunnel = [VSCTL_PATH , "add-port" , bridge ,
379+ name , "--" , "set" , "interface" ,
380+ name , "type=gre" , "options:key=%s" % gre_key ,
381+ "options:remote_ip=%s" % remote_ip ]
382+ do_cmd (add_tunnel )
383+ tunnel_setup = True
384+ # verify port
385+ verify_port = [VSCTL_PATH , "get" , "port" , name , "interfaces" ]
386+ res = do_cmd (verify_port )
387+ # Expecting python-style list as output
388+ iface_list = []
389+ if len (res ) > 2 :
390+ iface_list = res .strip ()[1 :- 1 ].split (',' )
391+ if len (iface_list ) != 1 :
392+ logging .debug ("WARNING: Unexpected output while verifying " +
393+ "port %s on bridge %s" % (name , bridge ))
394+ return "FAILURE:VERIFY_PORT_FAILED"
395+
396+ # verify interface
397+ iface_uuid = iface_list [0 ]
398+ verify_interface_key = [VSCTL_PATH , "get" , "interface" ,
399+ iface_uuid , "options:key" ]
400+ verify_interface_ip = [VSCTL_PATH , "get" , "interface" ,
401+ iface_uuid , "options:remote_ip" ]
402+
403+ key_validation = do_cmd (verify_interface_key )
404+ ip_validation = do_cmd (verify_interface_ip )
405+
406+ if not gre_key in key_validation or not remote_ip in ip_validation :
407+ logging .debug ("WARNING: Unexpected output while verifying " +
408+ "interface %s on bridge %s" % (name , bridge ))
409+ return "FAILURE:VERIFY_INTERFACE_FAILED"
410+ logging .debug ("Tunnel interface validated:%s" % verify_interface_ip )
411+ cmd_tun_ofport = [VSCTL_PATH , "get" , "interface" ,
412+ iface_uuid , "ofport" ]
413+ tun_ofport = do_cmd (cmd_tun_ofport )
414+ # Ensure no trailing LF
415+ if tun_ofport .endswith ('\n ' ):
416+ tun_ofport = tun_ofport [:- 1 ]
417+ # find xs network for this bridge, verify is used for ovs tunnel network
418+ xs_nw_uuid = do_cmd ([XE_PATH , "network-list" ,
419+ "bridge=%s" % bridge , "--minimal" ])
420+ ovs_tunnel_network = False
421+ try :
422+ ovs_tunnel_network = do_cmd ([XE_PATH ,"network-param-get" ,
423+ "uuid=%s" % xs_nw_uuid ,
424+ "param-name=other-config" ,
425+ "param-key=is-ovs-tun-network" , "--minimal" ])
426+ except :
427+ pass
428+
429+ ovs_vpc_distributed_vr_network = False
430+ try :
431+ ovs_vpc_distributed_vr_network = do_cmd ([XE_PATH ,"network-param-get" ,
432+ "uuid=%s" % xs_nw_uuid ,
433+ "param-name=other-config" ,
434+ "param-key=is-ovs-vpc-distributed-vr-network" , "--minimal" ])
435+ except :
436+ pass
437+
438+ if ovs_tunnel_network == 'True' :
439+ # add flow entryies for dropping broadcast coming in from gre tunnel
440+ add_flow (bridge , priority = 1000 , in_port = tun_ofport ,
441+ dl_dst = 'ff:ff:ff:ff:ff:ff' , actions = 'drop' )
442+ add_flow (bridge , priority = 1000 , in_port = tun_ofport ,
443+ nw_dst = '224.0.0.0/24' , actions = 'drop' )
444+ drop_flow_setup = True
445+ logging .debug ("Broadcast drop rules added" )
446+
447+ if ovs_vpc_distributed_vr_network == 'True' :
448+ # add flow rules for dropping broadcast coming in from tunnel ports
449+ add_flow (bridge , priority = 1000 , in_port = tun_ofport , table = 0 ,
450+ dl_dst = 'ff:ff:ff:ff:ff:ff' , actions = 'drop' )
451+ add_flow (bridge , priority = 1000 , in_port = tun_ofport , table = 0 ,
452+ nw_dst = '224.0.0.0/24' , actions = 'drop' )
453+
454+ # add flow rule to send the traffic from tunnel ports to L2 switching table only
455+ add_flow (bridge , priority = 1100 , in_port = tun_ofport , table = 0 , actions = 'resubmit(,1)' )
456+
457+ # mark tunnel interface with network id for which this tunnel was created
458+ do_cmd ([VSCTL_PATH , "set" , "interface" , name , "options:cloudstack-network-id=%s" % network_uuid ])
459+ update_flooding_rules_on_port_plug_unplug (bridge , name , 'online' , network_uuid )
460+
461+ logging .debug ("Successfully created tunnel from host %s" % src_host + " to host %s" % dst_host +
462+ " with GRE key %s" % gre_key )
463+ return "SUCCESS:%s creation succeeded" % name
464+ except :
465+ logging .debug ("An unexpected error occured. Rolling back" )
466+ if tunnel_setup :
467+ logging .debug ("Deleting GRE interface" )
468+ # Destroy GRE port and interface
469+ del_port (bridge , name )
470+ if drop_flow_setup :
471+ # Delete flows
472+ logging .debug ("Deleting flow entries from GRE interface" )
473+ del_flows (bridge , in_port = tun_ofport )
474+ # This will not cancel the original exception
475+ raise
476+
477+ # Configures the bridge created for a VPC that is enabled for distributed routing. Management server sends VPC
478+ # physical topology details (which VM from which tier running on which host etc). Based on the VPC physical topology L2
479+ # lookup table and L3 lookup tables are updated by this function.
349480def configure_vpc_bridge_for_network_topology (bridge , this_host_id , json_config , sequence_no ):
350481
351482 vpconfig = jsonLoader (json .loads (json_config )).vpc
@@ -412,8 +543,13 @@ def configure_vpc_bridge_for_network_topology(bridge, this_host_id, json_config,
412543 network = get_network_details (vpconfig , nic .networkuuid )
413544 gre_key = network .grekey
414545
415- # generate tunnel name as per the tunnel naming convention and get the OF port
546+ # generate tunnel name as per the tunnel naming convention
416547 tunnel_name = "t%s-%s-%s" % (gre_key , this_host_id , host .hostid )
548+
549+ # check if tunnel exists already, if not create a tunnel from this host to remote host
550+ if not check_tunnel_exists (bridge , tunnel_name ):
551+ create_tunnel (bridge , host .ipaddress , gre_key , this_host_id , host .hostid , network .networkuuid )
552+
417553 of_port = get_ofport_for_vif (tunnel_name )
418554
419555 # Add flow rule in L2 look up table, if packet's destination mac matches MAC of the VM's nic
@@ -441,10 +577,10 @@ def configure_vpc_bridge_for_network_topology(bridge, this_host_id, json_config,
441577 del_flows (bridge , table = L3_LOOKUP_TABLE )
442578
443579 ofspec .seek (0 )
444- logging .debug ("Adding below flows rules L2 & L3 lookup tables:\n " + ofspec .read ())
580+ logging .debug ("Adding below flows rules in L2 & L3 lookup tables:\n " + ofspec .read ())
581+ ofspec .close ()
445582
446583 # update bridge with the flow-rules for L2 lookup and L3 lookup in the file in one attempt
447- ofspec .close ()
448584 do_cmd ([OFCTL_PATH , 'add-flows' , bridge , ofspec_filename ])
449585
450586 # now that we updated the bridge with flow rules close and delete the file.
@@ -460,8 +596,9 @@ def configure_vpc_bridge_for_network_topology(bridge, this_host_id, json_config,
460596 os .remove (ofspec_filename )
461597 raise error_message
462598
463- # Configures the bridge created for a VPC enabled for distributed firewall. Management server sends VPC routing policies
464- # details. Based on the VPC routing policies ingress ACL table and egress ACL tables are updated by this function.
599+ # Configures the bridge created for a VPC that is enabled for distributed firewall. Management server sends VPC routing
600+ # policy (network ACL applied on the tiers etc) details. Based on the VPC routing policies ingress ACL table and
601+ # egress ACL tables are updated by this function.
465602def configure_vpc_bridge_for_routing_policies (bridge , json_config , sequence_no ):
466603
467604 vpconfig = jsonLoader (json .loads (json_config )).vpc
@@ -564,9 +701,9 @@ def configure_vpc_bridge_for_routing_policies(bridge, json_config, sequence_no):
564701
565702 ofspec .seek (0 )
566703 logging .debug ("Adding below flows rules Ingress & Egress ACL tables:\n " + ofspec .read ())
704+ ofspec .close ()
567705
568706 # update bridge with the flow-rules for ingress and egress ACL's added in the file in one attempt
569- ofspec .close ()
570707 do_cmd ([OFCTL_PATH , 'add-flows' , bridge , ofspec_filename ])
571708
572709 # now that we updated the bridge with flow rules delete the file.
@@ -658,9 +795,9 @@ class tier_ports:
658795
659796 ofspec .seek (0 )
660797 logging .debug ("Adding below flows rules L2 flooding table: \n " + ofspec .read ())
798+ ofspec .close ()
661799
662800 # update bridge with the flow-rules for broadcast rules added in the file in one attempt
663- ofspec .close ()
664801 do_cmd ([OFCTL_PATH , 'add-flows' , bridge , ofspec_filename ])
665802
666803 # now that we updated the bridge with flow rules delete the file.
0 commit comments