@@ -3,7 +3,9 @@ package network
33import (
44 "fmt"
55 "net"
6+ "strings"
67
8+ "github.com/Azure/azure-container-networking/iptables"
79 "github.com/Azure/azure-container-networking/log"
810 "github.com/Azure/azure-container-networking/netio"
911 "github.com/Azure/azure-container-networking/netlink"
@@ -16,9 +18,12 @@ import (
1618)
1719
1820const (
19- azureMac = "12:34:56:78:9a:bc" // Packets leaving the VM should have this MAC
20- loopbackIf = "lo" // The name of the loopback interface
21- numDefaultRoutes = 2 // VNET NS, when no containers use it, has this many routes
21+ azureMac = "12:34:56:78:9a:bc" // Packets leaving the VM should have this MAC
22+ loopbackIf = "lo" // The name of the loopback interface
23+ numDefaultRoutes = 2 // VNET NS, when no containers use it, has this many routes
24+ tunnelingTable = 2 // Packets not entering on the vlan interface go to this routing table
25+ tunnelingMark = 333 // The packets that are to tunnel will be marked with this number
26+ DisableRPFilterCmd = "sysctl -w net.ipv4.conf.all.rp_filter=0" // Command to disable the rp filter for tunneling
2227)
2328
2429type netnsClient interface {
@@ -229,13 +234,63 @@ func (client *TransparentVlanEndpointClient) PopulateVnet(epInfo *EndpointInfo)
229234 return errors .Wrap (err , "vnet veth doesn't exist" )
230235 }
231236 client .vnetMac = vnetVethIf .HardwareAddr
237+ // Disable rp filter again to allow asymmetric routing for tunneling packets
238+ _ , err = client .plClient .ExecuteCommand (DisableRPFilterCmd )
239+ if err != nil {
240+ return errors .Wrap (err , "transparent vlan failed to disable rp filter in vnet" )
241+ }
242+ disableRPFilterVlanIfCmd := strings .Replace (DisableRPFilterCmd , "all" , client .vlanIfName , 1 )
243+ _ , err = client .plClient .ExecuteCommand (disableRPFilterVlanIfCmd )
244+ if err != nil {
245+ return errors .Wrap (err , "transparent vlan failed to disable rp filter vlan interface in vnet" )
246+ }
232247 return nil
233248}
234249
235250func (client * TransparentVlanEndpointClient ) AddEndpointRules (epInfo * EndpointInfo ) error {
236251 if err := client .AddSnatEndpointRules (); err != nil {
237252 return errors .Wrap (err , "failed to add snat endpoint rules" )
238253 }
254+ log .Printf ("[transparent vlan] Adding tunneling rules in vnet namespace" )
255+ err := ExecuteInNS (client .vnetNSName , func () error {
256+ return client .AddVnetRules (epInfo )
257+ })
258+ return err
259+ }
260+
261+ // Add rules related to tunneling the packet outside of the VM, assumes all calls are idempotent. Namespace: vnet
262+ func (client * TransparentVlanEndpointClient ) AddVnetRules (epInfo * EndpointInfo ) error {
263+ // iptables -t mangle -I PREROUTING -j MARK --set-mark <TUNNELING MARK>
264+ markOption := fmt .Sprintf ("MARK --set-mark %d" , tunnelingMark )
265+ if err := iptables .InsertIptableRule (iptables .V4 , "mangle" , "PREROUTING" , "" , markOption ); err != nil {
266+ return errors .Wrap (err , "unable to insert iptables rule mark all packets not entering on vlan interface" )
267+ }
268+ // iptables -t mangle -I PREROUTING -j ACCEPT -i <VLAN IF>
269+ match := fmt .Sprintf ("-i %s" , client .vlanIfName )
270+ if err := iptables .InsertIptableRule (iptables .V4 , "mangle" , "PREROUTING" , match , "ACCEPT" ); err != nil {
271+ return errors .Wrap (err , "unable to insert iptables rule accept all incoming from vlan interface" )
272+ }
273+ // Packets that are marked should go to the tunneling table
274+ newRule := vishnetlink .NewRule ()
275+ newRule .Mark = tunnelingMark
276+ newRule .Table = tunnelingTable
277+ rules , err := vishnetlink .RuleList (vishnetlink .FAMILY_V4 )
278+ if err != nil {
279+ return errors .Wrap (err , "unable to get existing ip rule list" )
280+ }
281+ // Check if rule exists already
282+ ruleExists := false
283+ for index := range rules {
284+ if rules [index ].Mark == newRule .Mark {
285+ ruleExists = true
286+ }
287+ }
288+ if ! ruleExists {
289+ if err := vishnetlink .RuleAdd (newRule ); err != nil {
290+ return errors .Wrap (err , "failed to add rule that forwards packet with mark to tunneling routing table" )
291+ }
292+ }
293+
239294 return nil
240295}
241296
@@ -306,7 +361,7 @@ func (client *TransparentVlanEndpointClient) ConfigureContainerInterfacesAndRout
306361 }
307362 }
308363
309- if err := client .AddDefaultRoutes (client .containerVethName ); err != nil {
364+ if err := client .AddDefaultRoutes (client .containerVethName , 0 ); err != nil {
310365 return errors .Wrap (err , "failed container ns add default routes" )
311366 }
312367 if err := client .AddDefaultArp (client .containerVethName , client .vnetMac .String ()); err != nil {
@@ -324,8 +379,7 @@ func (client *TransparentVlanEndpointClient) ConfigureVnetInterfacesAndRoutesImp
324379
325380 // Add route specifying which device the pod ip(s) are on
326381 routeInfoList := client .GetVnetRoutes (epInfo .IPAddresses )
327-
328- if err = client .AddDefaultRoutes (client .vlanIfName ); err != nil {
382+ if err = client .AddDefaultRoutes (client .vlanIfName , 0 ); err != nil {
329383 return errors .Wrap (err , "failed vnet ns add default/gateway routes (idempotent)" )
330384 }
331385 if err = client .AddDefaultArp (client .vlanIfName , azureMac ); err != nil {
@@ -334,6 +388,9 @@ func (client *TransparentVlanEndpointClient) ConfigureVnetInterfacesAndRoutesImp
334388 if err = addRoutes (client .netlink , client .netioshim , client .vnetVethName , routeInfoList ); err != nil {
335389 return errors .Wrap (err , "failed adding routes to vnet specific to this container" )
336390 }
391+ if err = client .AddDefaultRoutes (client .vlanIfName , tunnelingTable ); err != nil {
392+ return errors .Wrap (err , "failed vnet ns add outbound routing table routes for tunneling (idempotent)" )
393+ }
337394 // Return to ConfigureContainerInterfacesAndRoutes
338395 return err
339396}
@@ -366,12 +423,13 @@ func (client *TransparentVlanEndpointClient) GetVnetRoutes(ipAddresses []net.IPN
366423// to the virtual gateway ip on linkToName device interface
367424// Route 1: 169.254.1.1 dev <linkToName>
368425// Route 2: default via 169.254.1.1 dev <linkToName>
369- func (client * TransparentVlanEndpointClient ) AddDefaultRoutes (linkToName string ) error {
426+ func (client * TransparentVlanEndpointClient ) AddDefaultRoutes (linkToName string , table int ) error {
370427 // Add route for virtualgwip (ip route add 169.254.1.1/32 dev eth0)
371428 virtualGwIP , virtualGwNet , _ := net .ParseCIDR (virtualGwIPString )
372429 routeInfo := RouteInfo {
373430 Dst : * virtualGwNet ,
374431 Scope : netlink .RT_SCOPE_LINK ,
432+ Table : table ,
375433 }
376434 // Difference between interface name in addRoutes and DevName: in RouteInfo?
377435 if err := addRoutes (client .netlink , client .netioshim , linkToName , []RouteInfo {routeInfo }); err != nil {
@@ -382,8 +440,9 @@ func (client *TransparentVlanEndpointClient) AddDefaultRoutes(linkToName string)
382440 _ , defaultIPNet , _ := net .ParseCIDR (defaultGwCidr )
383441 dstIP := net.IPNet {IP : net .ParseIP (defaultGw ), Mask : defaultIPNet .Mask }
384442 routeInfo = RouteInfo {
385- Dst : dstIP ,
386- Gw : virtualGwIP ,
443+ Dst : dstIP ,
444+ Gw : virtualGwIP ,
445+ Table : table ,
387446 }
388447
389448 if err := addRoutes (client .netlink , client .netioshim , linkToName , []RouteInfo {routeInfo }); err != nil {
0 commit comments