network: Detect and add static ARP entries

[ port from runtime commit 67d3e2c5c5d11738c0c0ff46b1228909a6c81ab0 ]

Some network plugins add static arp entries in the network namespace.
Scan namespace for static entries and pass these on to the
agent to be added within the guest.

If the grpc api is not implemented by the agent due to a older running
agent, check for this and do not error out to maintain
backward compatibility.

Signed-off-by: Archana Shinde <archana.m.shinde@intel.com>
Signed-off-by: Peng Tao <bergwolf@hyper.sh>
This commit is contained in:
Archana Shinde 2020-06-29 20:06:15 -07:00 committed by Peng Tao
parent 117ce4ac41
commit 520295b938
4 changed files with 138 additions and 20 deletions

View File

@ -110,6 +110,7 @@ const (
grpcUpdateInterfaceRequest = "grpc.UpdateInterfaceRequest" grpcUpdateInterfaceRequest = "grpc.UpdateInterfaceRequest"
grpcListInterfacesRequest = "grpc.ListInterfacesRequest" grpcListInterfacesRequest = "grpc.ListInterfacesRequest"
grpcListRoutesRequest = "grpc.ListRoutesRequest" grpcListRoutesRequest = "grpc.ListRoutesRequest"
grpcAddARPNeighborsRequest = "grpc.AddARPNeighborsRequest"
grpcOnlineCPUMemRequest = "grpc.OnlineCPUMemRequest" grpcOnlineCPUMemRequest = "grpc.OnlineCPUMemRequest"
grpcListProcessesRequest = "grpc.ListProcessesRequest" grpcListProcessesRequest = "grpc.ListProcessesRequest"
grpcUpdateContainerRequest = "grpc.UpdateContainerRequest" grpcUpdateContainerRequest = "grpc.UpdateContainerRequest"
@ -638,6 +639,30 @@ func (k *kataAgent) updateRoutes(routes []*vcTypes.Route) ([]*vcTypes.Route, err
return nil, nil return nil, nil
} }
func (k *kataAgent) addARPNeighbors(neighs []*vcTypes.ARPNeighbor) error {
if neighs != nil {
neighsReq := &grpc.AddARPNeighborsRequest{
Neighbors: &grpc.ARPNeighbors{
ARPNeighbors: k.convertToKataAgentNeighbors(neighs),
},
}
_, err := k.sendReq(neighsReq)
if err != nil {
if grpcStatus.Convert(err).Code() == codes.Unimplemented {
k.Logger().WithFields(logrus.Fields{
"arpneighbors-requested": fmt.Sprintf("%+v", neighs),
}).Warn("add ARP neighbors request failed due to old agent, please upgrade Kata Containers image version")
return nil
}
k.Logger().WithFields(logrus.Fields{
"arpneighbors-requested": fmt.Sprintf("%+v", neighs),
}).WithError(err).Error("add ARP neighbors request failed")
}
return err
}
return nil
}
func (k *kataAgent) listInterfaces() ([]*vcTypes.Interface, error) { func (k *kataAgent) listInterfaces() ([]*vcTypes.Interface, error) {
req := &grpc.ListInterfacesRequest{} req := &grpc.ListInterfacesRequest{}
resultingInterfaces, err := k.sendReq(req) resultingInterfaces, err := k.sendReq(req)
@ -843,7 +868,7 @@ func (k *kataAgent) startSandbox(sandbox *Sandbox) error {
// //
// Setup network interfaces and routes // Setup network interfaces and routes
// //
interfaces, routes, err := generateInterfacesAndRoutes(sandbox.networkNS) interfaces, routes, neighs, err := generateVCNetworkStructures(sandbox.networkNS)
if err != nil { if err != nil {
return err return err
} }
@ -853,6 +878,9 @@ func (k *kataAgent) startSandbox(sandbox *Sandbox) error {
if _, err = k.updateRoutes(routes); err != nil { if _, err = k.updateRoutes(routes); err != nil {
return err return err
} }
if err = k.addARPNeighbors(neighs); err != nil {
return err
}
storages := setupStorages(sandbox) storages := setupStorages(sandbox)
@ -1999,6 +2027,9 @@ func (k *kataAgent) installReqFunc(c *kataclient.AgentClient) {
k.reqHandlers[grpcListRoutesRequest] = func(ctx context.Context, req interface{}) (interface{}, error) { k.reqHandlers[grpcListRoutesRequest] = func(ctx context.Context, req interface{}) (interface{}, error) {
return k.client.AgentServiceClient.ListRoutes(ctx, req.(*grpc.ListRoutesRequest)) return k.client.AgentServiceClient.ListRoutes(ctx, req.(*grpc.ListRoutesRequest))
} }
k.reqHandlers[grpcAddARPNeighborsRequest] = func(ctx context.Context, req interface{}) (interface{}, error) {
return k.client.AgentServiceClient.AddARPNeighbors(ctx, req.(*grpc.AddARPNeighborsRequest))
}
k.reqHandlers[grpcOnlineCPUMemRequest] = func(ctx context.Context, req interface{}) (interface{}, error) { k.reqHandlers[grpcOnlineCPUMemRequest] = func(ctx context.Context, req interface{}) (interface{}, error) {
return k.client.AgentServiceClient.OnlineCPUMem(ctx, req.(*grpc.OnlineCPUMemRequest)) return k.client.AgentServiceClient.OnlineCPUMem(ctx, req.(*grpc.OnlineCPUMemRequest))
} }
@ -2175,18 +2206,27 @@ func (k *kataAgent) convertToIPFamily(ipFamily aTypes.IPFamily) int {
return netlink.FAMILY_V4 return netlink.FAMILY_V4
} }
func (k *kataAgent) convertToKataAgentIPAddress(ipAddr *vcTypes.IPAddress) (aIPAddr *aTypes.IPAddress) {
if ipAddr == nil {
return nil
}
aIPAddr = &aTypes.IPAddress{
Family: k.convertToKataAgentIPFamily(ipAddr.Family),
Address: ipAddr.Address,
Mask: ipAddr.Mask,
}
return aIPAddr
}
func (k *kataAgent) convertToKataAgentIPAddresses(ipAddrs []*vcTypes.IPAddress) (aIPAddrs []*aTypes.IPAddress) { func (k *kataAgent) convertToKataAgentIPAddresses(ipAddrs []*vcTypes.IPAddress) (aIPAddrs []*aTypes.IPAddress) {
for _, ipAddr := range ipAddrs { for _, ipAddr := range ipAddrs {
if ipAddr == nil { if ipAddr == nil {
continue continue
} }
aIPAddr := &aTypes.IPAddress{ aIPAddr := k.convertToKataAgentIPAddress(ipAddr)
Family: k.convertToKataAgentIPFamily(ipAddr.Family),
Address: ipAddr.Address,
Mask: ipAddr.Mask,
}
aIPAddrs = append(aIPAddrs, aIPAddr) aIPAddrs = append(aIPAddrs, aIPAddr)
} }
@ -2268,6 +2308,25 @@ func (k *kataAgent) convertToKataAgentRoutes(routes []*vcTypes.Route) (aRoutes [
return aRoutes return aRoutes
} }
func (k *kataAgent) convertToKataAgentNeighbors(neighs []*vcTypes.ARPNeighbor) (aNeighs []*aTypes.ARPNeighbor) {
for _, neigh := range neighs {
if neigh == nil {
continue
}
aNeigh := &aTypes.ARPNeighbor{
ToIPAddress: k.convertToKataAgentIPAddress(neigh.ToIPAddress),
Device: neigh.Device,
State: int32(neigh.State),
Lladdr: neigh.LLAddr,
}
aNeighs = append(aNeighs, aNeigh)
}
return aNeighs
}
func (k *kataAgent) convertToRoutes(aRoutes []*aTypes.Route) (routes []*vcTypes.Route) { func (k *kataAgent) convertToRoutes(aRoutes []*aTypes.Route) (routes []*vcTypes.Route) {
for _, aRoute := range aRoutes { for _, aRoute := range aRoutes {
if aRoute == nil { if aRoute == nil {

View File

@ -122,6 +122,7 @@ type NetworkInfo struct {
Addrs []netlink.Addr Addrs []netlink.Addr
Routes []netlink.Route Routes []netlink.Route
DNS DNSInfo DNS DNSInfo
Neighbors []netlink.Neigh
} }
// NetworkInterface defines a network interface. // NetworkInterface defines a network interface.
@ -942,14 +943,15 @@ func deleteNetNS(netNSPath string) error {
return nil return nil
} }
func generateInterfacesAndRoutes(networkNS NetworkNamespace) ([]*vcTypes.Interface, []*vcTypes.Route, error) { func generateVCNetworkStructures(networkNS NetworkNamespace) ([]*vcTypes.Interface, []*vcTypes.Route, []*vcTypes.ARPNeighbor, error) {
if networkNS.NetNsPath == "" { if networkNS.NetNsPath == "" {
return nil, nil, nil return nil, nil, nil, nil
} }
var routes []*vcTypes.Route var routes []*vcTypes.Route
var ifaces []*vcTypes.Interface var ifaces []*vcTypes.Interface
var neighs []*vcTypes.ARPNeighbor
for _, endpoint := range networkNS.Endpoints { for _, endpoint := range networkNS.Endpoints {
@ -1008,10 +1010,36 @@ func generateInterfacesAndRoutes(networkNS NetworkNamespace) ([]*vcTypes.Interfa
r.Device = endpoint.Name() r.Device = endpoint.Name()
r.Scope = uint32(route.Scope) r.Scope = uint32(route.Scope)
routes = append(routes, &r) routes = append(routes, &r)
}
for _, neigh := range endpoint.Properties().Neighbors {
var n vcTypes.ARPNeighbor
// We add only static ARP entries
if neigh.State != netlink.NUD_PERMANENT {
continue
}
n.Device = endpoint.Name()
n.State = neigh.State
n.Flags = neigh.Flags
if neigh.HardwareAddr != nil {
n.LLAddr = neigh.HardwareAddr.String()
}
n.ToIPAddress = &vcTypes.IPAddress{
Family: netlink.FAMILY_V4,
Address: neigh.IP.String(),
}
if neigh.IP.To4() == nil {
n.ToIPAddress.Family = netlink.FAMILY_V6
}
neighs = append(neighs, &n)
} }
} }
return ifaces, routes, nil return ifaces, routes, neighs, nil
} }
func createNetworkInterfacePair(idx int, ifName string, interworkingModel NetInterworkingModel) (NetworkInterfacePair, error) { func createNetworkInterfacePair(idx int, ifName string, interworkingModel NetInterworkingModel) (NetworkInterfacePair, error) {
@ -1071,6 +1099,11 @@ func networkInfoFromLink(handle *netlink.Handle, link netlink.Link) (NetworkInfo
return NetworkInfo{}, err return NetworkInfo{}, err
} }
neighbors, err := handle.NeighList(link.Attrs().Index, netlink.FAMILY_ALL)
if err != nil {
return NetworkInfo{}, err
}
return NetworkInfo{ return NetworkInfo{
Iface: NetlinkIface{ Iface: NetlinkIface{
LinkAttrs: *(link.Attrs()), LinkAttrs: *(link.Attrs()),
@ -1078,6 +1111,7 @@ func networkInfoFromLink(handle *netlink.Handle, link netlink.Link) (NetworkInfo
}, },
Addrs: addrs, Addrs: addrs,
Routes: routes, Routes: routes,
Neighbors: neighbors,
}, nil }, nil
} }

View File

@ -65,6 +65,12 @@ func TestGenerateInterfacesAndRoutes(t *testing.T) {
{LinkIndex: 329, Dst: nil, Src: nil, Gw: gatewayV6}, {LinkIndex: 329, Dst: nil, Src: nil, Gw: gatewayV6},
} }
arpMAC, _ := net.ParseMAC("6a:92:3a:59:70:aa")
neighs := []netlink.Neigh{
{LinkIndex: 329, IP: net.IPv4(192, 168, 0, 101), State: netlink.NUD_PERMANENT, HardwareAddr: arpMAC},
}
networkInfo := NetworkInfo{ networkInfo := NetworkInfo{
Iface: NetlinkIface{ Iface: NetlinkIface{
LinkAttrs: netlink.LinkAttrs{MTU: 1500}, LinkAttrs: netlink.LinkAttrs{MTU: 1500},
@ -72,6 +78,7 @@ func TestGenerateInterfacesAndRoutes(t *testing.T) {
}, },
Addrs: addrs, Addrs: addrs,
Routes: routes, Routes: routes,
Neighbors: neighs,
} }
ep0 := &PhysicalEndpoint{ ep0 := &PhysicalEndpoint{
@ -84,7 +91,7 @@ func TestGenerateInterfacesAndRoutes(t *testing.T) {
nns := NetworkNamespace{NetNsPath: "foobar", NetNsCreated: true, Endpoints: endpoints} nns := NetworkNamespace{NetNsPath: "foobar", NetNsCreated: true, Endpoints: endpoints}
resInterfaces, resRoutes, err := generateInterfacesAndRoutes(nns) resInterfaces, resRoutes, resNeighs, err := generateVCNetworkStructures(nns)
// //
// Build expected results: // Build expected results:
@ -106,6 +113,15 @@ func TestGenerateInterfacesAndRoutes(t *testing.T) {
{Dest: "", Gateway: "2001:db8:1::1", Device: "eth0", Source: ""}, {Dest: "", Gateway: "2001:db8:1::1", Device: "eth0", Source: ""},
} }
expectedNeighs := []*vcTypes.ARPNeighbor{
{
Device: "eth0",
State: netlink.NUD_PERMANENT,
LLAddr: "6a:92:3a:59:70:aa",
ToIPAddress: &vcTypes.IPAddress{Address: "192.168.0.101", Family: netlink.FAMILY_V4},
},
}
for _, r := range resRoutes { for _, r := range resRoutes {
fmt.Printf("resRoute: %+v\n", r) fmt.Printf("resRoute: %+v\n", r)
} }
@ -115,7 +131,8 @@ func TestGenerateInterfacesAndRoutes(t *testing.T) {
"Interfaces returned didn't match: got %+v, expecting %+v", resInterfaces, expectedInterfaces) "Interfaces returned didn't match: got %+v, expecting %+v", resInterfaces, expectedInterfaces)
assert.True(t, reflect.DeepEqual(resRoutes, expectedRoutes), assert.True(t, reflect.DeepEqual(resRoutes, expectedRoutes),
"Routes returned didn't match: got %+v, expecting %+v", resRoutes, expectedRoutes) "Routes returned didn't match: got %+v, expecting %+v", resRoutes, expectedRoutes)
assert.True(t, reflect.DeepEqual(resNeighs, expectedNeighs),
"ARP Neighbors returned didn't match: got %+v, expecting %+v", resNeighs, expectedNeighs)
} }
func TestNetInterworkingModelIsValid(t *testing.T) { func TestNetInterworkingModelIsValid(t *testing.T) {

View File

@ -39,3 +39,11 @@ type Route struct {
Source string Source string
Scope uint32 Scope uint32
} }
type ARPNeighbor struct {
ToIPAddress *IPAddress
Device string
LLAddr string
State int
Flags int
}