@@ -119,7 +119,8 @@ enum ovn_stage {
119
119
PIPELINE_STAGE (SWITCH , IN , DHCP_RESPONSE , 13 , "ls_in_dhcp_response ") \
120
120
PIPELINE_STAGE (SWITCH , IN , DNS_LOOKUP , 14 , "ls_in_dns_lookup ") \
121
121
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 ") \
123
124
\
124
125
/* Logical switch egress stages. */ \
125
126
PIPELINE_STAGE (SWITCH , OUT , PRE_LB , 0 , "ls_out_pre_lb ") \
@@ -2342,6 +2343,18 @@ ovn_port_update_sbrec(struct northd_context *ctx,
2342
2343
}
2343
2344
2344
2345
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
+ }
2345
2358
} else {
2346
2359
const char * chassis = NULL ;
2347
2360
if (op -> peer && op -> peer -> od && op -> peer -> od -> nbr ) {
@@ -3039,6 +3052,12 @@ lsp_is_up(const struct nbrec_logical_switch_port *lsp)
3039
3052
return !lsp -> up || * lsp -> up ;
3040
3053
}
3041
3054
3055
+ static bool
3056
+ lsp_is_external (const struct nbrec_logical_switch_port * nbsp )
3057
+ {
3058
+ return !strcmp (nbsp -> type , "external" );
3059
+ }
3060
+
3042
3061
static bool
3043
3062
build_dhcpv4_action (struct ovn_port * op , ovs_be32 offer_ip ,
3044
3063
struct ds * options_action , struct ds * response_action ,
@@ -3936,6 +3955,10 @@ build_acls(struct ovn_datapath *od, struct hmap *lflows,
3936
3955
* logical ports of the datapath if the CMS has configured DHCPv4 options.
3937
3956
* */
3938
3957
for (size_t i = 0 ; i < od -> nbs -> n_ports ; i ++ ) {
3958
+ if (lsp_is_external (od -> nbs -> ports [i ])) {
3959
+ continue ;
3960
+ }
3961
+
3939
3962
if (od -> nbs -> ports [i ]-> dhcpv4_options ) {
3940
3963
const char * server_id = smap_get (
3941
3964
& od -> nbs -> ports [i ]-> dhcpv4_options -> options , "server_id" );
@@ -4322,6 +4345,10 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
4322
4345
continue ;
4323
4346
}
4324
4347
4348
+ if (lsp_is_external (op -> nbsp )) {
4349
+ continue ;
4350
+ }
4351
+
4325
4352
ds_clear (& match );
4326
4353
ds_clear (& actions );
4327
4354
ds_put_format (& match , "inport == %s" , op -> json_key );
@@ -4388,6 +4415,10 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
4388
4415
continue ;
4389
4416
}
4390
4417
4418
+ if (lsp_is_external (op -> nbsp )) {
4419
+ continue ;
4420
+ }
4421
+
4391
4422
for (size_t i = 0 ; i < op -> n_lsp_addrs ; i ++ ) {
4392
4423
for (size_t j = 0 ; j < op -> lsp_addrs [i ].n_ipv4_addrs ; j ++ ) {
4393
4424
ds_clear (& match );
@@ -4496,6 +4527,14 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
4496
4527
continue ;
4497
4528
}
4498
4529
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
+
4499
4538
for (size_t i = 0 ; i < op -> n_lsp_addrs ; i ++ ) {
4500
4539
for (size_t j = 0 ; j < op -> lsp_addrs [i ].n_ipv4_addrs ; j ++ ) {
4501
4540
struct ds options_action = DS_EMPTY_INITIALIZER ;
@@ -4508,9 +4547,16 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
4508
4547
ds_put_format (
4509
4548
& match , "inport == %s && eth.src == %s && "
4510
4549
"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 ,
4512
4553
op -> lsp_addrs [i ].ea_s );
4513
4554
4555
+ if (is_external ) {
4556
+ ds_put_format (& match , " && is_chassis_resident(%s)" ,
4557
+ op -> json_key );
4558
+ }
4559
+
4514
4560
ovn_lflow_add (lflows , op -> od , S_SWITCH_IN_DHCP_OPTIONS ,
4515
4561
100 , ds_cstr (& match ),
4516
4562
ds_cstr (& options_action ));
@@ -4525,9 +4571,16 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
4525
4571
*/
4526
4572
ds_put_format (
4527
4573
& 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 ,
4529
4577
op -> lsp_addrs [i ].ea_s , ds_cstr (& ipv4_addr_match ));
4530
4578
4579
+ if (is_external ) {
4580
+ ds_put_format (& match , " && is_chassis_resident(%s)" ,
4581
+ op -> json_key );
4582
+ }
4583
+
4531
4584
ovn_lflow_add (lflows , op -> od , S_SWITCH_IN_DHCP_OPTIONS ,
4532
4585
100 , ds_cstr (& match ),
4533
4586
ds_cstr (& options_action ));
@@ -4538,8 +4591,16 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
4538
4591
ds_put_format (
4539
4592
& match , "inport == %s && eth.src == %s && "
4540
4593
"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 ,
4542
4597
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
+
4543
4604
ovn_lflow_add (lflows , op -> od , S_SWITCH_IN_DHCP_RESPONSE ,
4544
4605
100 , ds_cstr (& match ),
4545
4606
ds_cstr (& response_action ));
@@ -4560,9 +4621,16 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
4560
4621
ds_put_format (
4561
4622
& match , "inport == %s && eth.src == %s"
4562
4623
" && 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 ,
4564
4627
op -> lsp_addrs [i ].ea_s );
4565
4628
4629
+ if (is_external ) {
4630
+ ds_put_format (& match , " && is_chassis_resident(%s)" ,
4631
+ op -> json_key );
4632
+ }
4633
+
4566
4634
ovn_lflow_add (lflows , op -> od , S_SWITCH_IN_DHCP_OPTIONS , 100 ,
4567
4635
ds_cstr (& match ), ds_cstr (& options_action ));
4568
4636
@@ -4614,7 +4682,9 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
4614
4682
/* Ingress table 12 and 13: DHCP options and response, by default goto
4615
4683
* next. (priority 0).
4616
4684
* 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). */
4618
4688
4619
4689
HMAP_FOR_EACH (od , key_node , datapaths ) {
4620
4690
if (!od -> nbs ) {
@@ -4625,9 +4695,60 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
4625
4695
ovn_lflow_add (lflows , od , S_SWITCH_IN_DHCP_RESPONSE , 0 , "1" , "next;" );
4626
4696
ovn_lflow_add (lflows , od , S_SWITCH_IN_DNS_LOOKUP , 0 , "1" , "next;" );
4627
4697
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;" );
4628
4699
}
4629
4700
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
4631
4752
* (priority 100). */
4632
4753
HMAP_FOR_EACH (op , key_node , ports ) {
4633
4754
if (!op -> nbsp ) {
@@ -4647,9 +4768,9 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
4647
4768
"outport = \"" MC_FLOOD "\"; output;" );
4648
4769
}
4649
4770
4650
- /* Ingress table 16 : Destination lookup, unicast handling (priority 50), */
4771
+ /* Ingress table 17 : Destination lookup, unicast handling (priority 50), */
4651
4772
HMAP_FOR_EACH (op , key_node , ports ) {
4652
- if (!op -> nbsp ) {
4773
+ if (!op -> nbsp || lsp_is_external ( op -> nbsp ) ) {
4653
4774
continue ;
4654
4775
}
4655
4776
@@ -4766,7 +4887,7 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
4766
4887
}
4767
4888
}
4768
4889
4769
- /* Ingress table 16 : Destination lookup for unknown MACs (priority 0). */
4890
+ /* Ingress table 17 : Destination lookup for unknown MACs (priority 0). */
4770
4891
HMAP_FOR_EACH (od , key_node , datapaths ) {
4771
4892
if (!od -> nbs ) {
4772
4893
continue ;
@@ -4801,7 +4922,7 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
4801
4922
* Priority 150 rules drop packets to disabled logical ports, so that they
4802
4923
* don't even receive multicast or broadcast packets. */
4803
4924
HMAP_FOR_EACH (op , key_node , ports ) {
4804
- if (!op -> nbsp ) {
4925
+ if (!op -> nbsp || lsp_is_external ( op -> nbsp ) ) {
4805
4926
continue ;
4806
4927
}
4807
4928
0 commit comments