@@ -119,7 +119,8 @@ enum ovn_stage {
119119 PIPELINE_STAGE (SWITCH , IN , DHCP_RESPONSE , 13 , "ls_in_dhcp_response ") \
120120 PIPELINE_STAGE (SWITCH , IN , DNS_LOOKUP , 14 , "ls_in_dns_lookup ") \
121121 PIPELINE_STAGE (SWITCH , IN , DNS_RESPONSE , 15 , "ls_in_dns_response ") \
122- PIPELINE_STAGE (SWITCH , IN , L2_LKUP , 16 , "ls_in_l2_lkup ") \
122+ PIPELINE_STAGE (SWITCH , IN , EXTERNAL_PORT , 16 , "ls_in_external_port ") \
123+ PIPELINE_STAGE (SWITCH , IN , L2_LKUP , 17 , "ls_in_l2_lkup ") \
123124 \
124125 /* Logical switch egress stages. */ \
125126 PIPELINE_STAGE (SWITCH , OUT , PRE_LB , 0 , "ls_out_pre_lb ") \
@@ -2342,6 +2343,18 @@ ovn_port_update_sbrec(struct northd_context *ctx,
23422343 }
23432344
23442345 sbrec_port_binding_set_nat_addresses (op -> sb , NULL , 0 );
2346+
2347+ if (!strcmp (op -> nbsp -> type , "external" )) {
2348+ if (op -> nbsp -> ha_chassis_group ) {
2349+ sync_ha_chassis_group_for_sbpb (
2350+ ctx , op -> nbsp -> ha_chassis_group ,
2351+ sbrec_chassis_by_name , op -> sb );
2352+ sset_add (active_ha_chassis_grps ,
2353+ op -> nbsp -> ha_chassis_group -> name );
2354+ } else {
2355+ sbrec_port_binding_set_ha_chassis_group (op -> sb , NULL );
2356+ }
2357+ }
23452358 } else {
23462359 const char * chassis = NULL ;
23472360 if (op -> peer && op -> peer -> od && op -> peer -> od -> nbr ) {
@@ -3039,6 +3052,12 @@ lsp_is_up(const struct nbrec_logical_switch_port *lsp)
30393052 return !lsp -> up || * lsp -> up ;
30403053}
30413054
3055+ static bool
3056+ lsp_is_external (const struct nbrec_logical_switch_port * nbsp )
3057+ {
3058+ return !strcmp (nbsp -> type , "external" );
3059+ }
3060+
30423061static bool
30433062build_dhcpv4_action (struct ovn_port * op , ovs_be32 offer_ip ,
30443063 struct ds * options_action , struct ds * response_action ,
@@ -3936,6 +3955,10 @@ build_acls(struct ovn_datapath *od, struct hmap *lflows,
39363955 * logical ports of the datapath if the CMS has configured DHCPv4 options.
39373956 * */
39383957 for (size_t i = 0 ; i < od -> nbs -> n_ports ; i ++ ) {
3958+ if (lsp_is_external (od -> nbs -> ports [i ])) {
3959+ continue ;
3960+ }
3961+
39393962 if (od -> nbs -> ports [i ]-> dhcpv4_options ) {
39403963 const char * server_id = smap_get (
39413964 & od -> nbs -> ports [i ]-> dhcpv4_options -> options , "server_id" );
@@ -4322,6 +4345,10 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
43224345 continue ;
43234346 }
43244347
4348+ if (lsp_is_external (op -> nbsp )) {
4349+ continue ;
4350+ }
4351+
43254352 ds_clear (& match );
43264353 ds_clear (& actions );
43274354 ds_put_format (& match , "inport == %s" , op -> json_key );
@@ -4388,6 +4415,10 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
43884415 continue ;
43894416 }
43904417
4418+ if (lsp_is_external (op -> nbsp )) {
4419+ continue ;
4420+ }
4421+
43914422 for (size_t i = 0 ; i < op -> n_lsp_addrs ; i ++ ) {
43924423 for (size_t j = 0 ; j < op -> lsp_addrs [i ].n_ipv4_addrs ; j ++ ) {
43934424 ds_clear (& match );
@@ -4496,6 +4527,14 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
44964527 continue ;
44974528 }
44984529
4530+ bool is_external = lsp_is_external (op -> nbsp );
4531+ if (is_external && (!op -> od -> localnet_port ||
4532+ !op -> nbsp -> ha_chassis_group )) {
4533+ /* If it's an external port and there is no localnet port
4534+ * and if it doesn't belong to an HA chassis group ignore it. */
4535+ continue ;
4536+ }
4537+
44994538 for (size_t i = 0 ; i < op -> n_lsp_addrs ; i ++ ) {
45004539 for (size_t j = 0 ; j < op -> lsp_addrs [i ].n_ipv4_addrs ; j ++ ) {
45014540 struct ds options_action = DS_EMPTY_INITIALIZER ;
@@ -4508,9 +4547,16 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
45084547 ds_put_format (
45094548 & match , "inport == %s && eth.src == %s && "
45104549 "ip4.src == 0.0.0.0 && ip4.dst == 255.255.255.255 && "
4511- "udp.src == 68 && udp.dst == 67" , op -> json_key ,
4550+ "udp.src == 68 && udp.dst == 67" ,
4551+ is_external ? op -> od -> localnet_port -> json_key :
4552+ op -> json_key ,
45124553 op -> lsp_addrs [i ].ea_s );
45134554
4555+ if (is_external ) {
4556+ ds_put_format (& match , " && is_chassis_resident(%s)" ,
4557+ op -> json_key );
4558+ }
4559+
45144560 ovn_lflow_add (lflows , op -> od , S_SWITCH_IN_DHCP_OPTIONS ,
45154561 100 , ds_cstr (& match ),
45164562 ds_cstr (& options_action ));
@@ -4525,9 +4571,16 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
45254571 */
45264572 ds_put_format (
45274573 & match , "inport == %s && eth.src == %s && "
4528- "%s && udp.src == 68 && udp.dst == 67" , op -> json_key ,
4574+ "%s && udp.src == 68 && udp.dst == 67" ,
4575+ is_external ? op -> od -> localnet_port -> json_key :
4576+ op -> json_key ,
45294577 op -> lsp_addrs [i ].ea_s , ds_cstr (& ipv4_addr_match ));
45304578
4579+ if (is_external ) {
4580+ ds_put_format (& match , " && is_chassis_resident(%s)" ,
4581+ op -> json_key );
4582+ }
4583+
45314584 ovn_lflow_add (lflows , op -> od , S_SWITCH_IN_DHCP_OPTIONS ,
45324585 100 , ds_cstr (& match ),
45334586 ds_cstr (& options_action ));
@@ -4538,8 +4591,16 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
45384591 ds_put_format (
45394592 & match , "inport == %s && eth.src == %s && "
45404593 "ip4 && udp.src == 68 && udp.dst == 67"
4541- " && " REGBIT_DHCP_OPTS_RESULT , op -> json_key ,
4594+ " && " REGBIT_DHCP_OPTS_RESULT ,
4595+ is_external ? op -> od -> localnet_port -> json_key :
4596+ op -> json_key ,
45424597 op -> lsp_addrs [i ].ea_s );
4598+
4599+ if (is_external ) {
4600+ ds_put_format (& match , " && is_chassis_resident(%s)" ,
4601+ op -> json_key );
4602+ }
4603+
45434604 ovn_lflow_add (lflows , op -> od , S_SWITCH_IN_DHCP_RESPONSE ,
45444605 100 , ds_cstr (& match ),
45454606 ds_cstr (& response_action ));
@@ -4560,9 +4621,16 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
45604621 ds_put_format (
45614622 & match , "inport == %s && eth.src == %s"
45624623 " && ip6.dst == ff02::1:2 && udp.src == 546 &&"
4563- " udp.dst == 547" , op -> json_key ,
4624+ " udp.dst == 547" ,
4625+ is_external ? op -> od -> localnet_port -> json_key :
4626+ op -> json_key ,
45644627 op -> lsp_addrs [i ].ea_s );
45654628
4629+ if (is_external ) {
4630+ ds_put_format (& match , " && is_chassis_resident(%s)" ,
4631+ op -> json_key );
4632+ }
4633+
45664634 ovn_lflow_add (lflows , op -> od , S_SWITCH_IN_DHCP_OPTIONS , 100 ,
45674635 ds_cstr (& match ), ds_cstr (& options_action ));
45684636
@@ -4614,7 +4682,9 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
46144682 /* Ingress table 12 and 13: DHCP options and response, by default goto
46154683 * next. (priority 0).
46164684 * Ingress table 14 and 15: DNS lookup and response, by default goto next.
4617- * (priority 0).*/
4685+ * (priority 0).
4686+ * Ingress table 16 - External port handling, by default goto next.
4687+ * (priority 0). */
46184688
46194689 HMAP_FOR_EACH (od , key_node , datapaths ) {
46204690 if (!od -> nbs ) {
@@ -4625,9 +4695,60 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
46254695 ovn_lflow_add (lflows , od , S_SWITCH_IN_DHCP_RESPONSE , 0 , "1" , "next;" );
46264696 ovn_lflow_add (lflows , od , S_SWITCH_IN_DNS_LOOKUP , 0 , "1" , "next;" );
46274697 ovn_lflow_add (lflows , od , S_SWITCH_IN_DNS_RESPONSE , 0 , "1" , "next;" );
4698+ ovn_lflow_add (lflows , od , S_SWITCH_IN_EXTERNAL_PORT , 0 , "1" , "next;" );
46284699 }
46294700
4630- /* Ingress table 16: Destination lookup, broadcast and multicast handling
4701+ HMAP_FOR_EACH (op , key_node , ports ) {
4702+ if (!op -> nbsp || !lsp_is_external (op -> nbsp ) ||
4703+ !op -> od -> localnet_port ) {
4704+ continue ;
4705+ }
4706+
4707+ /* Table 16: External port. Drop ARP request for router ips from
4708+ * external ports on chassis not binding those ports.
4709+ * This makes the router pipeline to be run only on the chassis
4710+ * binding the external ports. */
4711+
4712+ for (size_t i = 0 ; i < op -> n_lsp_addrs ; i ++ ) {
4713+ for (size_t j = 0 ; j < op -> od -> n_router_ports ; j ++ ) {
4714+ struct ovn_port * rp = op -> od -> router_ports [j ];
4715+ for (size_t k = 0 ; k < rp -> n_lsp_addrs ; k ++ ) {
4716+ for (size_t l = 0 ; l < rp -> lsp_addrs [k ].n_ipv4_addrs ;
4717+ l ++ ) {
4718+ ds_clear (& match );
4719+ ds_put_format (
4720+ & match , "inport == %s && eth.src == %s"
4721+ " && !is_chassis_resident(%s)"
4722+ " && arp.tpa == %s && arp.op == 1" ,
4723+ op -> od -> localnet_port -> json_key ,
4724+ op -> lsp_addrs [i ].ea_s , op -> json_key ,
4725+ rp -> lsp_addrs [k ].ipv4_addrs [l ].addr_s );
4726+ ovn_lflow_add (lflows , op -> od ,
4727+ S_SWITCH_IN_EXTERNAL_PORT , 100 ,
4728+ ds_cstr (& match ), "drop;" );
4729+ }
4730+ for (size_t l = 0 ; l < rp -> lsp_addrs [k ].n_ipv6_addrs ;
4731+ l ++ ) {
4732+ ds_clear (& match );
4733+ ds_put_format (
4734+ & match , "inport == %s && eth.src == %s"
4735+ " && !is_chassis_resident(%s)"
4736+ " && nd_ns && ip6.dst == {%s, %s} && "
4737+ "nd.target == %s" ,
4738+ op -> od -> localnet_port -> json_key ,
4739+ op -> lsp_addrs [i ].ea_s , op -> json_key ,
4740+ rp -> lsp_addrs [k ].ipv6_addrs [l ].addr_s ,
4741+ rp -> lsp_addrs [k ].ipv6_addrs [l ].sn_addr_s ,
4742+ rp -> lsp_addrs [k ].ipv6_addrs [l ].addr_s );
4743+ ovn_lflow_add (lflows , op -> od ,
4744+ S_SWITCH_IN_EXTERNAL_PORT , 100 ,
4745+ ds_cstr (& match ), "drop;" );
4746+ }
4747+ }
4748+ }
4749+ }
4750+ }
4751+ /* Ingress table 17: Destination lookup, broadcast and multicast handling
46314752 * (priority 100). */
46324753 HMAP_FOR_EACH (op , key_node , ports ) {
46334754 if (!op -> nbsp ) {
@@ -4647,9 +4768,9 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
46474768 "outport = \"" MC_FLOOD "\"; output;" );
46484769 }
46494770
4650- /* Ingress table 16 : Destination lookup, unicast handling (priority 50), */
4771+ /* Ingress table 17 : Destination lookup, unicast handling (priority 50), */
46514772 HMAP_FOR_EACH (op , key_node , ports ) {
4652- if (!op -> nbsp ) {
4773+ if (!op -> nbsp || lsp_is_external ( op -> nbsp ) ) {
46534774 continue ;
46544775 }
46554776
@@ -4766,7 +4887,7 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
47664887 }
47674888 }
47684889
4769- /* Ingress table 16 : Destination lookup for unknown MACs (priority 0). */
4890+ /* Ingress table 17 : Destination lookup for unknown MACs (priority 0). */
47704891 HMAP_FOR_EACH (od , key_node , datapaths ) {
47714892 if (!od -> nbs ) {
47724893 continue ;
@@ -4801,7 +4922,7 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
48014922 * Priority 150 rules drop packets to disabled logical ports, so that they
48024923 * don't even receive multicast or broadcast packets. */
48034924 HMAP_FOR_EACH (op , key_node , ports ) {
4804- if (!op -> nbsp ) {
4925+ if (!op -> nbsp || lsp_is_external ( op -> nbsp ) ) {
48054926 continue ;
48064927 }
48074928
0 commit comments